gio-miniprogram-sdk 4.3.1 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.github/workflows/publish.yml +3 -3
  2. package/dist/alipay.js +1 -1
  3. package/dist/baidu.js +1 -1
  4. package/dist/bytedance.js +1 -1
  5. package/dist/jingdong.js +1 -1
  6. package/dist/kuaishou.js +1 -1
  7. package/dist/plugins/gioABTest.js +1 -1
  8. package/dist/plugins/gioCompress.js +1 -1
  9. package/dist/plugins/gioEventAutoTracking.js +1 -1
  10. package/dist/plugins/gioImpressionTracking.js +1 -1
  11. package/dist/plugins/gioMultipleInstances.js +1 -1
  12. package/dist/plugins/gioPerformance.js +1 -0
  13. package/dist/qq.js +1 -1
  14. package/dist/quickapp.js +1 -1
  15. package/dist/taobao.js +1 -1
  16. package/dist/taro.js +1 -1
  17. package/dist/uniapp.js +1 -1
  18. package/dist/wechat.js +1 -1
  19. package/dist/xiaohongshu.js +1 -0
  20. package/package.json +12 -6
  21. package/rollup.config.js +9 -6
  22. package/rollup.plugins.config.js +1 -1
  23. package/src/constants/emitMsg.ts +1 -0
  24. package/src/core/dataStore/eventHooks/appEffects.ts +3 -0
  25. package/src/core/dataStore/eventHooks/index.ts +4 -2
  26. package/src/core/dataStore/eventHooks/pageEffects.ts +1 -0
  27. package/src/core/growingIO.ts +27 -3
  28. package/src/core/uploader.ts +12 -3
  29. package/src/core/userStore.ts +1 -2
  30. package/src/minipInstance/base.ts +62 -25
  31. package/src/minipInstance/framework.ts +3 -1
  32. package/src/minipInstance/my.ts +40 -0
  33. package/src/minipInstance/quickapp.ts +23 -6
  34. package/src/minipInstance/wx.ts +15 -0
  35. package/src/minipInstance/xhs.ts +20 -0
  36. package/src/platformConfig/base.ts +1 -0
  37. package/src/platformConfig/xhs.ts +20 -0
  38. package/src/plugins/gioABTest.ts +32 -3
  39. package/src/plugins/gioEventAutoTracking.ts +99 -1
  40. package/src/plugins/gioImpressionTracking.ts +3 -1
  41. package/src/plugins/gioPerformance/exception.ts +152 -0
  42. package/src/plugins/gioPerformance/monitor.ts +284 -0
  43. package/src/plugins/gioPerformance/network.ts +197 -0
  44. package/src/plugins/gioPerformance.ts +131 -0
  45. package/src/types/base.ts +5 -1
  46. package/src/types/minipInstance.ts +3 -1
  47. package/src/types/platforms.ts +3 -0
  48. package/src/utils/tools.ts +46 -3
  49. package/src/utils/verifiers.ts +4 -3
  50. package/tsconfig.json +1 -1
  51. package/typings/global.d.ts +8 -0
  52. package/bin/build.sh +0 -38
@@ -0,0 +1,197 @@
1
+ import { GrowingIOType } from '@@/types/growingIO';
2
+ import {
3
+ compact,
4
+ forEach,
5
+ isArray,
6
+ isEmpty,
7
+ isNil,
8
+ isRegExp,
9
+ isString,
10
+ unset
11
+ } from '@@/utils/glodash';
12
+
13
+ export default class Network {
14
+ private minipInst: any;
15
+ private excludeRegExp: RegExp | string | any[];
16
+ private gdpRequestURL: string;
17
+ private buildNetworkEvent: (attributes: any) => void;
18
+ constructor(public growingIO: GrowingIOType, public options: any = {}) {
19
+ this.minipInst = this.growingIO.minipInstance.minip;
20
+ this.buildNetworkEvent = (attributes: any) => {
21
+ if (!options.network) {
22
+ return;
23
+ }
24
+ const { duration, url, method, statusCode } = attributes;
25
+ this.growingIO.plugins.gioPerformance?.buildPerfEvent(
26
+ 'apm_network_request',
27
+ {
28
+ response_duration: duration,
29
+ request_address: url,
30
+ request_method: method,
31
+ http_code: statusCode
32
+ }
33
+ );
34
+ };
35
+
36
+ if (this.options.network?.exclude) {
37
+ this.excludeRegExp = this.options.network.exclude;
38
+ }
39
+ this.hookRequest();
40
+ // 重写生成地址的方法,sdk在性能分析时需要拿到主实例的请求地址做判断用
41
+ const self = this;
42
+ const originFunc = this.growingIO.uploader.generateURL;
43
+ this.growingIO.uploader.generateURL = function () {
44
+ const result = originFunc.apply(this, arguments);
45
+ const trackingId = arguments[0];
46
+ if (trackingId === self.growingIO.trackingId) {
47
+ self.gdpRequestURL = result;
48
+ }
49
+ return result;
50
+ };
51
+ }
52
+
53
+ // 检验url是否符合过滤条件
54
+ verifyUrl = (url: string) => {
55
+ // Gio的请求直接过滤
56
+ if (url.indexOf(this.gdpRequestURL) > -1) {
57
+ return true;
58
+ }
59
+ // 正则或字符串域名数组过滤
60
+ if (isArray(this.excludeRegExp)) {
61
+ const verifyResult = compact(
62
+ (this.excludeRegExp as any[]).map((re: RegExp | string) => {
63
+ if (isRegExp(re)) {
64
+ return (re as RegExp).test(url);
65
+ } else if (isString(re)) {
66
+ return url.indexOf(re as string) > -1;
67
+ }
68
+ })
69
+ );
70
+ return !isEmpty(verifyResult);
71
+ } else if (isString(this.excludeRegExp)) {
72
+ // 单个字符串过滤校验
73
+ return url.indexOf(this.excludeRegExp as string) > -1;
74
+ } else if (isRegExp(this.excludeRegExp)) {
75
+ // 单个正则过滤校验
76
+ return (this.excludeRegExp as RegExp).test(url);
77
+ } else {
78
+ return false;
79
+ }
80
+ };
81
+
82
+ // 重写request
83
+ hookRequest = () => {
84
+ const self = this;
85
+ ['request', 'downloadFile', 'uploadFile'].forEach((reqKey: string) => {
86
+ const originRequest = this.minipInst[reqKey];
87
+ Object.defineProperty(this.minipInst, reqKey, {
88
+ writable: true,
89
+ enumerable: true,
90
+ configurable: true,
91
+ value: function (...args: any[]) {
92
+ const options: any = args[0];
93
+ const { url } = options;
94
+ // 如果符合过滤条件就直接发请求不做处理
95
+ if (self.verifyUrl(url)) {
96
+ return originRequest.call(this, options);
97
+ }
98
+ let cstmRequestInfo: any = {
99
+ header: options.header || {},
100
+ url: options.url
101
+ };
102
+ switch (reqKey) {
103
+ case 'request':
104
+ const { method } = options;
105
+ cstmRequestInfo = { ...cstmRequestInfo, method };
106
+ break;
107
+ case 'downloadFile':
108
+ case 'uploadFile':
109
+ const { filePath } = options;
110
+ cstmRequestInfo = {
111
+ ...cstmRequestInfo,
112
+ filePath,
113
+ method: reqKey === 'downloadFile' ? 'GET' : 'POST'
114
+ };
115
+ break;
116
+ default:
117
+ break;
118
+ }
119
+
120
+ const originFail = options.fail;
121
+ const fail = function (result: any) {
122
+ cstmRequestInfo.endTime = Date.now();
123
+ self.growingIO.plugins.gioPerformance?.buildPerfEvent('Error', {
124
+ error_type: result.errMsg,
125
+ error_content: cstmRequestInfo.url
126
+ });
127
+ if (typeof originFail === 'function') {
128
+ return originFail(result);
129
+ }
130
+ };
131
+
132
+ const originSuccess = options.success;
133
+ const success = function (result) {
134
+ cstmRequestInfo.endTime = Date.now();
135
+ self.networkPerfBuilder(result, cstmRequestInfo);
136
+ if (typeof originSuccess === 'function') {
137
+ return originSuccess(result);
138
+ }
139
+ };
140
+ cstmRequestInfo.startTime = Date.now();
141
+ return originRequest.call(this, {
142
+ ...options,
143
+ success,
144
+ fail
145
+ });
146
+ }
147
+ });
148
+ });
149
+ };
150
+
151
+ // 请求性能数据组装
152
+ networkPerfBuilder = (requestResult: any, cstmRequestInfo: any) => {
153
+ const { profile = {}, statusCode = 0, errMsg } = requestResult;
154
+ const { url, filePath, method } = cstmRequestInfo;
155
+ const {
156
+ redirectStart,
157
+ redirectEnd,
158
+ fetchStart,
159
+ domainLookUpStart,
160
+ domainLookUpEnd,
161
+ connectStart,
162
+ connectEnd,
163
+ requestStart,
164
+ responseStart,
165
+ responseEnd
166
+ } = profile;
167
+ const p = !isEmpty(profile);
168
+ const networkPerf = {
169
+ url,
170
+ filePath,
171
+ method,
172
+ statusCode,
173
+ message: errMsg,
174
+ // 重定向耗时(重定向没有发生,或者其中一个重定向非同源,则该值为 0)
175
+ redirect: p ? redirectEnd - redirectStart : 0,
176
+ // 缓存耗时
177
+ cache: p ? domainLookUpStart - fetchStart : 0,
178
+ // dns域名解析耗时
179
+ dns: p ? domainLookUpEnd - domainLookUpStart : 0,
180
+ // tcp链接耗时
181
+ tcp: p ? connectEnd - connectStart : 0,
182
+ // 在SSL链接建立好后,从客户端发送至服务端首次响应的耗时
183
+ request: p ? responseStart - requestStart : 0,
184
+ // 从服务端首次响应至数据完全响应完的耗时
185
+ response: p ? responseEnd - responseStart : 0,
186
+ // 请求总耗时
187
+ duration: p
188
+ ? responseEnd - fetchStart
189
+ : cstmRequestInfo.endTime - cstmRequestInfo.startTime
190
+ };
191
+ forEach(
192
+ networkPerf,
193
+ (v, k) => (v === '' || isNil(v)) && unset(networkPerf, k)
194
+ );
195
+ this.buildNetworkEvent(networkPerf);
196
+ };
197
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * 名称:性能采集插件
3
+ * 用途:用于采集小程序基本性能信息。
4
+ */
5
+ import { GrowingIOType } from '@@/types/growingIO';
6
+ import { isEmpty } from '@@/utils/glodash';
7
+ import { limitObject } from '@@/utils/tools';
8
+ import EMIT_MSG from '@@/constants/emitMsg';
9
+ import Exception from './gioPerformance/exception';
10
+ import Monitor from './gioPerformance/monitor';
11
+ import Network from './gioPerformance/network';
12
+
13
+ let ut;
14
+ class GioPerformance {
15
+ public pluginVersion: string;
16
+ public network: any;
17
+ public exception: any;
18
+ public monitor: any;
19
+ // 缓存队列,SDK初始化完成之后再根据性能的配置项发送数据
20
+ private cacheQueue: any[];
21
+ constructor(public growingIO: GrowingIOType, public options: any = {}) {
22
+ this.pluginVersion = '__PLUGIN_VERSION__';
23
+ ut = this.growingIO.utils;
24
+ this.options = {
25
+ monitor: true,
26
+ exception: true,
27
+ network: false,
28
+ ...this.options
29
+ };
30
+ this.cacheQueue = [];
31
+ this.growingIO.emitter.on(EMIT_MSG.SDK_INITIALIZED, (vdsConfig: any) => {
32
+ if (vdsConfig.trackingId === this.growingIO.trackingId) {
33
+ // 初始化配置项优先级更高(后续版本考虑把配置项值放在插件options上去配,弱化初始化配置项)
34
+ const { monitor, exception, network } = vdsConfig.performance;
35
+ if (monitor !== this.options.monitor) {
36
+ this.options.monitor = monitor;
37
+ }
38
+ if (exception !== this.options.exception) {
39
+ this.options.exception = exception;
40
+ }
41
+ if (network !== this.options.network) {
42
+ this.options.network = network;
43
+ }
44
+ this.init();
45
+ }
46
+ });
47
+ // 采集开关从关闭到打开时要把队列中存的启动和错误都发出去
48
+ // 采集开关开启必会更新session
49
+ this.growingIO.emitter?.on(EMIT_MSG.SESSIONID_UPDATE, () => {
50
+ const { trackingId, getOption } = this.growingIO;
51
+ if (getOption(trackingId, 'dataCollect')) {
52
+ this.sendCacheQuene();
53
+ }
54
+ });
55
+ }
56
+
57
+ init = () => {
58
+ const { dataCollect } = this.growingIO.vdsConfig;
59
+ const { monitor, exception, network } = this.options;
60
+ if (monitor) {
61
+ this.monitor = new Monitor(this.growingIO);
62
+ }
63
+ if (exception) {
64
+ this.exception = new Exception(this.growingIO);
65
+ }
66
+ if (network) {
67
+ this.network = new Network(this.growingIO, this.options);
68
+ }
69
+ // SDK初始化完成发送缓存队列
70
+ if (dataCollect) {
71
+ this.sendCacheQuene();
72
+ }
73
+ };
74
+
75
+ // 发送缓存队列
76
+ sendCacheQuene = () => {
77
+ if (!ut.isEmpty(this.cacheQueue)) {
78
+ this.cacheQueue.forEach((o: any) => {
79
+ this.buildPerfEvent(o.eventName, o.attributes, o.extra);
80
+ });
81
+ this.cacheQueue = [];
82
+ }
83
+ };
84
+
85
+ // 构建各种性能事件
86
+ buildPerfEvent = (eventName: string, attributes: any, extra?: any) => {
87
+ const {
88
+ dataStore: { eventContextBuilder, eventConverter },
89
+ gioSDKInitialized,
90
+ vdsConfig
91
+ } = this.growingIO;
92
+ // SDK没初始化完成或初始化关闭采集开关的事件先存起来,等SDK初始化完成或开启采集开关再发
93
+ if (!gioSDKInitialized || !vdsConfig.dataCollect) {
94
+ this.cacheQueue = [
95
+ ...this.cacheQueue,
96
+ {
97
+ eventName,
98
+ attributes,
99
+ extra
100
+ }
101
+ ];
102
+ return false;
103
+ }
104
+ // 处理过长的小数,保留0位
105
+ ut.forEach(attributes, (v, k) => {
106
+ if (Number.isNaN(v) || ut.isNil(v) || Number(v) < 0) {
107
+ attributes[k] = 0;
108
+ }
109
+ attributes[k] = ut.fixed(v, 0);
110
+ });
111
+ let event = {
112
+ eventType: 'CUSTOM',
113
+ eventName,
114
+ attributes,
115
+ ...eventContextBuilder(this.growingIO.trackingId)
116
+ };
117
+ event.attributes = limitObject({
118
+ ...(event.attributes ?? {}),
119
+ ...attributes
120
+ });
121
+ if (!isEmpty(extra)) {
122
+ event = { ...event, ...extra };
123
+ }
124
+ eventConverter(event);
125
+ };
126
+ }
127
+
128
+ export default {
129
+ name: 'gioPerformance',
130
+ method: GioPerformance
131
+ };
package/src/types/base.ts CHANGED
@@ -36,7 +36,11 @@ export interface UserOptions {
36
36
  // session保活时长(5分钟)
37
37
  keepAlive: number;
38
38
  // 性能采集配置
39
- performance?: { monitor: boolean; exception: boolean };
39
+ performance?: {
40
+ monitor: boolean;
41
+ exception: boolean;
42
+ network: boolean;
43
+ };
40
44
  // 请求超时时长
41
45
  requestTimeout?: number;
42
46
  // 数据上报域名
@@ -54,7 +54,7 @@ export interface Location {
54
54
  }
55
55
 
56
56
  export interface MinipInstanceType {
57
- // 小程序原生对象 wx/my/tt/swan/qq/ks
57
+ // 小程序原生对象 wx/my/tt/swan/qq/ks/jd/xhs
58
58
  readonly minip: any;
59
59
  // 当前平台
60
60
  platform: PLATFORMS;
@@ -123,4 +123,6 @@ export interface MinipInstanceType {
123
123
  getSystemInfo?: () => Promise<SystemInfo>;
124
124
  // 获取小程序设置
125
125
  getSetting?: () => any;
126
+ // 监听网络变更
127
+ setNetworkStatusListener?: () => any;
126
128
  }
@@ -7,6 +7,7 @@ export type PLATFORMS =
7
7
  | 'bytedance'
8
8
  | 'kuaishoup'
9
9
  | 'jdp'
10
+ | 'xhsp'
10
11
  | 'quickapp';
11
12
  export type PLATFORMTYPES =
12
13
  | 'wx'
@@ -17,6 +18,7 @@ export type PLATFORMTYPES =
17
18
  | 'tt'
18
19
  | 'ks'
19
20
  | 'jd'
21
+ | 'xhs'
20
22
  | 'quickapp';
21
23
 
22
24
  export type FRAMEWORKS = 'taro' | 'uniapp' | 'full';
@@ -27,6 +29,7 @@ export interface PlatformConfigType {
27
29
  scnPrefix?: string;
28
30
  appHandlers?: string[];
29
31
  pageHandlers?: string[];
32
+ shareEventTypes?: string[];
30
33
  actionEventTypes?: string[];
31
34
  hooks?: {
32
35
  App: boolean;
@@ -126,8 +126,13 @@ export const getOS = (system: any, configName: string) => {
126
126
  return `${configName}-Android`;
127
127
  } else if (lowsys.indexOf('ios') !== -1) {
128
128
  return `${configName}-iOS`;
129
+ } else if (
130
+ lowsys.indexOf('harmonyos') !== -1 ||
131
+ lowsys.indexOf('ohos') !== -1
132
+ ) {
133
+ return `${configName}-HarmonyOS`;
129
134
  } else {
130
- return system;
135
+ return `${configName}-${system}`;
131
136
  }
132
137
  }
133
138
  };
@@ -214,10 +219,13 @@ export const getPlainMinip = (platform?: string) => {
214
219
  return ks;
215
220
  case 'jd':
216
221
  return jd;
222
+ case 'xhs':
223
+ return xhs;
217
224
  // 第三方框架下自动获取实例
218
225
  // 百度等小程序中可能存在封装过的wx对象,因此wx要放在最后判断
219
226
  default: {
220
227
  let minip;
228
+ if (!minip) minip = niceTry(() => xhs);
221
229
  if (!minip) minip = niceTry(() => swan);
222
230
  if (!minip) minip = niceTry(() => my);
223
231
  if (!minip) minip = niceTry(() => tt);
@@ -251,6 +259,8 @@ export const getPlainConfig = (platform?: string) => {
251
259
  return __ksConfig; // 新版快手小程序已经拿不到了
252
260
  case 'jd':
253
261
  return __jdConfig;
262
+ case 'xhs':
263
+ return __MP_APP_JSON_MIGRATION__ ?? __MP_APP_JSON__;
254
264
  // 第三方框架下自动获取实例
255
265
  default:
256
266
  // 支付宝和淘宝不存在可获取的全局对象
@@ -259,10 +269,30 @@ export const getPlainConfig = (platform?: string) => {
259
269
  });
260
270
  };
261
271
 
272
+ export const getPlainAppCode = (platform?: string) => {
273
+ return niceTry(() => {
274
+ switch (platform) {
275
+ // 指定平台获取实例
276
+ case 'wx':
277
+ case 'qq':
278
+ return __wxAppCode__;
279
+ case 'tt':
280
+ return __allConfig__;
281
+ case 'ks':
282
+ return __module__;
283
+ case 'jd':
284
+ return __jdAppCode__;
285
+ default:
286
+ return undefined;
287
+ }
288
+ });
289
+ };
290
+
262
291
  // 在框架下自动获取当前平台值
263
292
  export const getPlainPlatform = () => {
264
293
  // 百度等小程序中可能存在封装过的wx对象,因此wx要放在最后判断
265
294
  let platform;
295
+ if (!platform && niceTry(() => xhs)) platform = 'xhs';
266
296
  if (!platform && niceTry(() => swan)) platform = 'swan';
267
297
  if (!platform && niceTry(() => tt)) platform = 'tt';
268
298
  if (!platform && niceTry(() => qq)) platform = 'qq';
@@ -416,11 +446,24 @@ export const hashCode = (string: string, abs = false) => {
416
446
  return abs ? Math.abs(hash) : hash;
417
447
  };
418
448
 
449
+ export const getExtraData = (data: any) => {
450
+ if (isString(data)) {
451
+ return niceTry(() => JSON.parse(data)) ?? {};
452
+ } else {
453
+ return data ?? {};
454
+ }
455
+ };
456
+
419
457
  // 获取额外的启动参数并合并进query
420
- export const getLaunchQuery = (originQuery: any = {}, extraData: any = {}) => {
458
+ export const getLaunchQuery = (originQuery: any = {}, data: any = {}) => {
421
459
  const validData = {};
460
+ const extraData = getExtraData(data);
422
461
  keys(extraData).forEach((k: string) => {
423
- if (['string', 'number', 'boolean'].includes(typeOf(extraData[k]))) {
462
+ // 排除掉新版圈选用的标记字段
463
+ if (
464
+ k !== 'gdpCircleRoomCollectUrl' &&
465
+ ['string', 'number', 'boolean'].includes(typeOf(extraData[k]))
466
+ ) {
424
467
  validData[k] = extraData[k];
425
468
  }
426
469
  });
@@ -7,12 +7,13 @@ import { isNumber, isString, toString } from '@@/utils/glodash';
7
7
 
8
8
  /**
9
9
  * 一些id的合法性校验
10
- * @param id // 只允许数字和字符串,不允许为空字符串、0、负数
10
+ * @param id // 只允许数字和字符串,不允许为空字符串、0、负数、短横线字符串null,undefined
11
11
  */
12
12
 
13
13
  export const verifyId = (o: string | number) =>
14
- (isString(o) && (o as string).length > 0) ||
15
- (isNumber(o) && (o as number) > 0);
14
+ ((isString(o) && (o as string).length > 0) ||
15
+ (isNumber(o) && (o as number) > 0)) &&
16
+ !['-', 'null', 'undefined'].includes(o as string);
16
17
 
17
18
  /**
18
19
  * 初始化时的一些合法性校验
package/tsconfig.json CHANGED
@@ -12,7 +12,7 @@
12
12
  "sourceMap": true,
13
13
  "strict": false,
14
14
  "lib": ["DOM", "ES5", "ES6", "ES2016", "ES2017"],
15
- "target": "ES6",
15
+ "target": "ES5",
16
16
  "types": ["node", "webpack-env"],
17
17
  "paths": {
18
18
  "@@/*": ["src/*"]
@@ -24,14 +24,22 @@ declare var qq: any;
24
24
  declare var tt: any;
25
25
  declare var ks: any;
26
26
  declare var jd: any;
27
+ declare var xhs: any;
27
28
  declare var quickapp: any;
29
+ declare var __wxAppCode__: any;
28
30
  declare var __wxConfig: any;
29
31
  declare var appConfig: any; // swan的全局配置
30
32
  declare var __myConfig: any; // my的全局配置
33
+ declare var TMAConfig: any; // tt的全局配置
31
34
  declare var __ttConfig: any; // tt的全局配置
35
+ declare var __allConfig__: any;
32
36
  declare var __qqConfig: any; // qq的全局配置
33
37
  declare var __ksConfig: any; // ks的全局配置
38
+ declare var __module__: any;
34
39
  declare var __jdConfig: any; // jd的全局配置
40
+ declare var __jdAppCode__: any;
41
+ declare var __MP_APP_JSON_MIGRATION__: any; // xhs的全局配置
42
+ declare var __MP_APP_JSON__: any; // xhs的全局配置
35
43
  declare var __proto__: any;
36
44
  declare var Taro: any
37
45
  declare var uni: any
package/bin/build.sh DELETED
@@ -1,38 +0,0 @@
1
- # 清空产物
2
- rm -r dist/*
3
-
4
- # 微信小程序
5
- npm run build:wx
6
-
7
- # 支付宝小程序
8
- npm run build:my
9
-
10
- # 百度小程序
11
- npm run build:swan
12
-
13
- # 字节小程序
14
- npm run build:tt
15
-
16
- # 京东小程序
17
- npm run build:jd
18
-
19
- # QQ小程序
20
- npm run build:qq
21
-
22
- # 淘宝小程序
23
- npm run build:tb
24
-
25
- # 快手小程序
26
- npm run build:ks
27
-
28
- # 快应用
29
- npm run build:quickapp
30
-
31
- # uniapp vue2/vue3
32
- npm run build:uniapp
33
-
34
- # taro2/3 react/vue2/vue3
35
- npm run build:taro
36
-
37
- # 插件
38
- npm run build:plugins