gio-miniprogram-sdk 4.0.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 (103) hide show
  1. package/.babelrc +4 -0
  2. package/.eslintignore +11 -0
  3. package/.eslintrc.js +120 -0
  4. package/.github/workflows/greetings.yml +13 -0
  5. package/.github/workflows/publish.yml +43 -0
  6. package/.prettierignore +19 -0
  7. package/.prettierrc.js +9 -0
  8. package/LICENSE +674 -0
  9. package/README.md +103 -0
  10. package/babel.config.js +6 -0
  11. package/bin/build/all.sh +38 -0
  12. package/bin/build/full.sh +32 -0
  13. package/bin/build/jd.sh +14 -0
  14. package/bin/build/ks.sh +14 -0
  15. package/bin/build/my.sh +14 -0
  16. package/bin/build/plugins.sh +5 -0
  17. package/bin/build/qq.sh +14 -0
  18. package/bin/build/quickapp.sh +14 -0
  19. package/bin/build/swan.sh +14 -0
  20. package/bin/build/taro.sh +18 -0
  21. package/bin/build/tb.sh +18 -0
  22. package/bin/build/tt.sh +14 -0
  23. package/bin/build/uniapp.sh +18 -0
  24. package/bin/build/wx.sh +14 -0
  25. package/dist/alipay.js +1 -0
  26. package/dist/baidu.js +1 -0
  27. package/dist/bytedance.js +1 -0
  28. package/dist/jingdong.js +1 -0
  29. package/dist/kuaishou.js +1 -0
  30. package/dist/plugins/gioABTest.js +1 -0
  31. package/dist/plugins/gioCompress.js +1 -0
  32. package/dist/plugins/gioEventAutoTracking.js +1 -0
  33. package/dist/plugins/gioImpressionTracking.js +1 -0
  34. package/dist/qq.js +1 -0
  35. package/dist/quickapp.js +1 -0
  36. package/dist/taobao.js +1 -0
  37. package/dist/taro.js +1 -0
  38. package/dist/uniapp.js +1 -0
  39. package/dist/wechat.js +1 -0
  40. package/package.json +144 -0
  41. package/rollup.config.js +92 -0
  42. package/rollup.plugins.config.js +76 -0
  43. package/src/constants/config.ts +136 -0
  44. package/src/constants/regex.ts +4 -0
  45. package/src/core/dataStore/eventContextBuilder.ts +70 -0
  46. package/src/core/dataStore/eventHooks/appEffects.ts +220 -0
  47. package/src/core/dataStore/eventHooks/index.ts +403 -0
  48. package/src/core/dataStore/eventHooks/minipPage.ts +132 -0
  49. package/src/core/dataStore/eventHooks/pageEffects.ts +168 -0
  50. package/src/core/dataStore/index.ts +543 -0
  51. package/src/core/growingIO.ts +433 -0
  52. package/src/core/plugins.ts +152 -0
  53. package/src/core/uploader.ts +219 -0
  54. package/src/core/userStore.ts +203 -0
  55. package/src/index.ts +68 -0
  56. package/src/minipInstance/base.ts +287 -0
  57. package/src/minipInstance/framework.ts +22 -0
  58. package/src/minipInstance/jd.ts +11 -0
  59. package/src/minipInstance/ks.ts +12 -0
  60. package/src/minipInstance/my.ts +53 -0
  61. package/src/minipInstance/qq.ts +12 -0
  62. package/src/minipInstance/quickapp.ts +230 -0
  63. package/src/minipInstance/swan.ts +20 -0
  64. package/src/minipInstance/tb.ts +53 -0
  65. package/src/minipInstance/tt.ts +12 -0
  66. package/src/minipInstance/wx.ts +12 -0
  67. package/src/platformConfig/base.ts +86 -0
  68. package/src/platformConfig/framework.ts +29 -0
  69. package/src/platformConfig/jd.ts +11 -0
  70. package/src/platformConfig/ks.ts +11 -0
  71. package/src/platformConfig/my.ts +15 -0
  72. package/src/platformConfig/qq.ts +13 -0
  73. package/src/platformConfig/quickapp.ts +48 -0
  74. package/src/platformConfig/swan.ts +11 -0
  75. package/src/platformConfig/tb.ts +29 -0
  76. package/src/platformConfig/tt.ts +11 -0
  77. package/src/platformConfig/wx.ts +20 -0
  78. package/src/pluginsOut/README.md +50 -0
  79. package/src/pluginsOut/frameworks/gioTaobaoAdapter.ts +195 -0
  80. package/src/pluginsOut/frameworks/gioTaroAdapter.ts +358 -0
  81. package/src/pluginsOut/frameworks/gioUniAppAdapter.ts +220 -0
  82. package/src/pluginsOut/ordinary/gioABTest.ts +254 -0
  83. package/src/pluginsOut/ordinary/gioCompress.ts +251 -0
  84. package/src/pluginsOut/ordinary/gioCustomTracking.ts +71 -0
  85. package/src/pluginsOut/ordinary/gioEventAutoTracking.ts +164 -0
  86. package/src/pluginsOut/ordinary/gioImpressionTracking.ts +298 -0
  87. package/src/types/base.ts +150 -0
  88. package/src/types/dataStore.ts +43 -0
  89. package/src/types/eventHooks.ts +141 -0
  90. package/src/types/gioCustomTracking.ts +9 -0
  91. package/src/types/gioEventTracking.ts +10 -0
  92. package/src/types/gioPerformance.ts +8 -0
  93. package/src/types/growingIO.ts +102 -0
  94. package/src/types/minipInstance.ts +126 -0
  95. package/src/types/platforms.ts +65 -0
  96. package/src/types/plugins.ts +24 -0
  97. package/src/types/uploader.ts +26 -0
  98. package/src/types/userStore.ts +22 -0
  99. package/src/utils/glodash.ts +423 -0
  100. package/src/utils/tools.ts +384 -0
  101. package/src/utils/verifiers.ts +76 -0
  102. package/tsconfig.json +32 -0
  103. package/typings/global.d.ts +92 -0
@@ -0,0 +1,433 @@
1
+ import {
2
+ isArray,
3
+ isEmpty,
4
+ isFunction,
5
+ isNil,
6
+ isObject,
7
+ keys,
8
+ toString,
9
+ unset
10
+ } from '@@/utils/glodash';
11
+ import {
12
+ callError,
13
+ consoleText,
14
+ eventNameValidate,
15
+ getAppInst,
16
+ getPlainPlatform,
17
+ guid,
18
+ limitObject
19
+ } from '@@/utils/tools';
20
+ import { ALLOWED_MODIFY_OPTIONS } from '@@/constants/config';
21
+ import { DataStoreType, OriginOptions } from '@@/types/dataStore';
22
+ import { FRAMEWORKS, PLATFORMTYPES } from '@@/types/platforms';
23
+ import { GrowingIOType } from '@@/types/growingIO';
24
+ import { MinipInstanceType } from '@@/types/minipInstance';
25
+ import { PluginsType } from '@@/types/plugins';
26
+ import { UploaderType } from '@@/types/uploader';
27
+ import { UserStoreType } from '@@/types/userStore';
28
+ import { verifyId } from '@@/utils/verifiers';
29
+ import * as glodash from '@@/utils/glodash';
30
+ import * as tools from '@@/utils/tools';
31
+ import DataStore from './dataStore';
32
+ import mitt from 'mitt';
33
+ import platformConfig from '__GIO_PLATFORM_CONFIG__';
34
+ import PlatformInstance from '__GIO_PLATFORM_INSTANCE__';
35
+ import Plugins from '@@/core/plugins';
36
+ import qs from 'querystringify';
37
+ import Uploader from './uploader';
38
+ import UserStore from '@@/core/userStore';
39
+
40
+ // SDK全局参数 版本号、小程序平台、框架名称、运行环境 均由打包工具替换写入
41
+ const sdkVersion: any = '__SDK_VERSION__';
42
+ const gioPlatform: any = '__GIO_PLATFORM__';
43
+ const gioFramework: any = '__GIO_FRAMEWORK__';
44
+
45
+ class GrowingIO implements GrowingIOType {
46
+ public utils: any;
47
+ public emitter: any;
48
+ public gioPlatform: PLATFORMTYPES;
49
+ public gioFramework: FRAMEWORKS;
50
+ public sdkVersion: string;
51
+ public inPlugin: boolean;
52
+ public subKey: string;
53
+ public platformConfig: any;
54
+ public gioSDKInitialized: boolean;
55
+ public vdsConfig: OriginOptions;
56
+ public minipInstance: MinipInstanceType;
57
+ public userStore: UserStoreType;
58
+ public dataStore: DataStoreType;
59
+ public plugins: PluginsType;
60
+ public uploader: UploaderType;
61
+
62
+ constructor() {
63
+ this.utils = { ...glodash, ...tools, qs };
64
+ this.emitter = mitt();
65
+ // 小程序平台
66
+ this.gioPlatform =
67
+ gioPlatform === 'framework' ? getPlainPlatform() : gioPlatform;
68
+ // 框架
69
+ this.gioFramework = gioFramework;
70
+ // sdk版本号
71
+ this.sdkVersion = sdkVersion;
72
+ // 是否在小程序插件中
73
+ try {
74
+ // 没有getApp方法或没有App方法的认为在插件中
75
+ if (
76
+ this.gioPlatform === 'quickapp' ||
77
+ (isFunction(getApp) && isFunction(App))
78
+ ) {
79
+ this.inPlugin = false;
80
+ } else {
81
+ this.inPlugin = true;
82
+ }
83
+ } catch (error) {
84
+ this.inPlugin = true;
85
+ }
86
+ if (this.inPlugin) {
87
+ consoleText('未检测到小程序实例,自动切换为插件模式!', 'info');
88
+ }
89
+ // 小程序实例配置
90
+ this.platformConfig = platformConfig;
91
+ // 小程序实例
92
+ this.minipInstance = new PlatformInstance(this);
93
+ // 数据中心实例
94
+ this.dataStore = new DataStore(this);
95
+ // 用户实例
96
+ this.userStore = new UserStore(this);
97
+ // 插件管理实例
98
+ this.plugins = new Plugins(this);
99
+ // 加载内置插件
100
+ this.plugins.innerPluginInit();
101
+ // 数据管理实例和上传实例均在各自环境中继承实现
102
+ }
103
+
104
+ // 手动注册插件
105
+ registerPlugins = (plugins: any) => {
106
+ this.plugins.pluginItems = [...this.plugins.pluginItems, ...plugins];
107
+ this.plugins.installAll(plugins);
108
+ };
109
+
110
+ // SDK初始化方法
111
+ init = (args: any) => {
112
+ consoleText('Gio小程序SDK 初始化中...', 'info');
113
+ // 初始化全局配置
114
+ this.dataStore.initOptions(args);
115
+ // 广播基础配置初始化完成
116
+ this.emitter?.emit('OPTION_INITIALIZED', this);
117
+ // 标记SDK已初始化完成
118
+ this.gioSDKInitialized = true;
119
+ // 初始化完成后把实例注入到小程序全局
120
+ // ?注意不要轻易修改实例挂载的地方(这里指app),会影响分包插件和运营SDK的实例取值
121
+ if (!this.vdsConfig.subpackage) {
122
+ const app = getAppInst();
123
+ // 直接挂载对象,存在问题:Page.data 触发深拷贝 存在循环引用会导致死循环
124
+ app.__gio__ = () => {
125
+ return this;
126
+ };
127
+ }
128
+ // 初始化请求逻辑
129
+ this.uploader = new Uploader(this);
130
+ // 没有开启IDMapping的时候要把userKey清掉,防止之前有数被带到上报数据里
131
+ if (!this.vdsConfig.idMapping) {
132
+ this.userStore.userKey = '';
133
+ }
134
+ // 广播SDK初始化完成
135
+ this.emitter.emit('SDK_INITIALIZED', this);
136
+ consoleText('Gio小程序SDK 初始化完成!', 'success');
137
+ if (this.vdsConfig.forceLogin) {
138
+ consoleText(
139
+ 'forceLogin已开启,请调用 identify 方法设置 openId 以继续上报!',
140
+ 'info'
141
+ );
142
+ }
143
+ // 在插件中手动触发visit
144
+ if (this.inPlugin && this.minipInstance.platform !== 'tbp') {
145
+ this.dataStore.sendVisit();
146
+ }
147
+ return true;
148
+ };
149
+
150
+ // 运行中获取配置
151
+ getOption = (k?: string) => this.dataStore.getOption(k);
152
+
153
+ // 运行中修改配置
154
+ setOption = (k: string, v: any) => {
155
+ if (keys(ALLOWED_MODIFY_OPTIONS).includes(k)) {
156
+ const r = this.dataStore.setOption(k, v);
157
+ if (r && ALLOWED_MODIFY_OPTIONS[k]) {
158
+ consoleText(
159
+ `已${v ? '开启' : '关闭'}${ALLOWED_MODIFY_OPTIONS[k]}`,
160
+ 'info'
161
+ );
162
+ }
163
+ return r;
164
+ } else {
165
+ consoleText(`不存在可修改的配置项:${k},请检查后重试!`, 'warn');
166
+ return false;
167
+ }
168
+ };
169
+
170
+ // 获取设备ID(匿名用户ID)
171
+ getDeviceId = () => this.userStore.uid;
172
+
173
+ // 设置设备ID,一般为openId
174
+ identify = (assignmentId: string | number) => {
175
+ if (this.vdsConfig.forceLogin) {
176
+ if (!verifyId(assignmentId)) {
177
+ callError('identify');
178
+ return;
179
+ }
180
+ // 截取长度
181
+ const asId = toString(assignmentId).slice(0, 1000);
182
+ // 在之后的请求中使用assignmentId作为uid(deviceId)使用
183
+ this.userStore.uid = asId;
184
+ // 为已积压的请求使用assignmentId全部赋值deviceId
185
+ this.uploader.hoardingQueue.forEach(
186
+ (o, i) => (this.uploader.hoardingQueue[i].deviceId = asId)
187
+ );
188
+ this.dataStore.setOption('forceLogin', false);
189
+ // 发送积压队列中的请求
190
+ this.uploader.initiateRequest(true);
191
+ } else {
192
+ callError('identify', !1, 'forceLogin未开启');
193
+ }
194
+ };
195
+
196
+ // 设置登录用户Id
197
+ setUserId = (userId: string | number, userKey?: string) => {
198
+ if (verifyId(userId)) {
199
+ // 切换userId要重设session补发visit
200
+ const prevId = this.userStore.gioId;
201
+ userId = toString(userId).slice(0, 1000);
202
+ userKey = toString(userKey).slice(0, 1000);
203
+ this.userStore.userId = userId;
204
+ if (this.vdsConfig.idMapping) {
205
+ this.userStore.userKey = isNil(userKey) ? '' : userKey;
206
+ }
207
+ // 切换userId时重置session并补发visit
208
+ if (prevId && prevId !== userId) {
209
+ this.userStore.sessionId = '';
210
+ const { path, query, settedTitle } =
211
+ this.dataStore.eventHooks.currentPage;
212
+ // 重新获取页面title,防止切换配置前修改了title没取到
213
+ this.dataStore.eventHooks.currentPage.title =
214
+ settedTitle[path] ||
215
+ this.minipInstance.getPageTitle(this.minipInstance.getCurrentPage());
216
+ // visit取当前页面值
217
+ this.dataStore.sendVisit({ path, query });
218
+ }
219
+ } else {
220
+ callError('setUserId');
221
+ }
222
+ };
223
+
224
+ // 清除登录用户Id
225
+ clearUserId = () => {
226
+ this.userStore.userId = undefined;
227
+ this.userStore.userKey = undefined;
228
+ };
229
+
230
+ // 发送用户属性
231
+ setUserAttributes = (userAttributes: any) => {
232
+ if (!isEmpty(userAttributes) && isObject(userAttributes)) {
233
+ this.plugins?.gioCustomTracking?.buildUserAttributesEvent(userAttributes);
234
+ } else {
235
+ callError('setUserAttributes');
236
+ }
237
+ };
238
+
239
+ // 自定义埋点事件
240
+ track = (name: string, properties: { [key: string]: string | string[] }) => {
241
+ const customEvent =
242
+ this.plugins?.gioCustomTracking?.buildCustomEvent || function () {};
243
+ customEvent(name, {
244
+ ...this.dataStore.generalProps,
245
+ ...(isObject(properties) && !isEmpty(properties) ? properties : {})
246
+ });
247
+ };
248
+
249
+ // 初始化事件计时器
250
+ trackTimerStart = (eventName: string) => {
251
+ if (this.vdsConfig.dataCollect) {
252
+ return eventNameValidate(eventName, () => {
253
+ const timerId = guid();
254
+ this.dataStore.trackTimers[timerId] = {
255
+ eventName,
256
+ leng: 0,
257
+ start: +Date.now()
258
+ };
259
+ return timerId;
260
+ });
261
+ }
262
+ return false;
263
+ };
264
+
265
+ // 暂停事件计时器
266
+ trackTimerPause = (timerId: string) => {
267
+ if (timerId && this.dataStore.trackTimers[timerId]) {
268
+ const tracker = this.dataStore.trackTimers[timerId];
269
+ if (tracker.start) {
270
+ tracker.leng = tracker.leng + (+Date.now() - tracker.start);
271
+ }
272
+ tracker.start = 0;
273
+ return true;
274
+ }
275
+ return false;
276
+ };
277
+
278
+ // 恢复事件计时器
279
+ trackTimerResume = (timerId: string) => {
280
+ if (timerId && this.dataStore.trackTimers[timerId]) {
281
+ const tracker = this.dataStore.trackTimers[timerId];
282
+ if (tracker.start === 0) {
283
+ tracker.start = +Date.now();
284
+ }
285
+ return true;
286
+ }
287
+ return false;
288
+ };
289
+
290
+ // 停止事件计时器并上报事件
291
+ trackTimerEnd = (timerId: string, attributes: any) => {
292
+ if (this.vdsConfig.dataCollect) {
293
+ const maxEnd = 60 * 60 * 24 * 1000;
294
+ if (timerId && this.dataStore.trackTimers[timerId]) {
295
+ const tracker = this.dataStore.trackTimers[timerId];
296
+ if (tracker.start !== 0) {
297
+ const shortCut = +Date.now() - tracker.start;
298
+ tracker.leng = shortCut > 0 ? tracker.leng + shortCut : 0;
299
+ }
300
+ // 要直接构建custom事件,不要去调用埋点插件的方法,万一插件没有加载就发不出去了
301
+ const { eventContextBuilder, eventInterceptor } = this.dataStore;
302
+ const event = {
303
+ eventType: 'CUSTOM',
304
+ eventName: tracker.eventName,
305
+ attributes: limitObject({
306
+ ...attributes,
307
+ event_duration: tracker.leng > maxEnd ? 0 : tracker.leng / 1000
308
+ }),
309
+ ...eventContextBuilder(),
310
+ customEventType: 0
311
+ };
312
+ eventInterceptor(event);
313
+ this.removeTimer(timerId);
314
+ return true;
315
+ } else {
316
+ consoleText('未查找到对应的计时器,请检查!', 'error');
317
+ return false;
318
+ }
319
+ }
320
+ return false;
321
+ };
322
+
323
+ // 移除事件计时器
324
+ removeTimer = (timerId: string) => {
325
+ if (timerId && this.dataStore.trackTimers[timerId]) {
326
+ delete this.dataStore.trackTimers[timerId];
327
+ return true;
328
+ }
329
+ return false;
330
+ };
331
+
332
+ // 清除所有事件计时器
333
+ clearTrackTimer = () => {
334
+ this.dataStore.trackTimers = {};
335
+ };
336
+
337
+ // 设置埋点事件的通用属性(即每个埋点事件都会带上的属性值)
338
+ setGeneralProps = (properties: any) => {
339
+ if (isObject(properties) && !isEmpty(properties)) {
340
+ this.dataStore.generalProps = {
341
+ ...this.dataStore.generalProps,
342
+ ...properties
343
+ };
344
+ keys(this.dataStore.generalProps).forEach((k: string) => {
345
+ if ([undefined, null].includes(this.dataStore.generalProps[k])) {
346
+ this.dataStore.generalProps[k] = '';
347
+ }
348
+ });
349
+ } else {
350
+ callError('setGeneralProps');
351
+ }
352
+ };
353
+
354
+ // 清空已设置的埋点事件的通用属性
355
+ clearGeneralProps = (properties: string[] | undefined) => {
356
+ if (isArray(properties) && !isEmpty(properties)) {
357
+ properties.forEach((prop: string) => {
358
+ unset(this.dataStore.generalProps, prop);
359
+ });
360
+ } else {
361
+ this.dataStore.generalProps = {};
362
+ }
363
+ };
364
+
365
+ // 设置页面属性
366
+ setPageAttributes = (properties: any) => {
367
+ const { currentPage } = this.dataStore.eventHooks;
368
+ // 这个currentPath一般认为是在onLoad中获取的当前小程序页面的path,此时SDK还没有parse,保存的还是上一个页面的信息
369
+ const currentPath = this.minipInstance.getCurrentPath();
370
+ if (['onLoad', 'attached'].includes(currentPage.currentLifecycle)) {
371
+ currentPage.pageProps[currentPath] = limitObject(properties);
372
+ }
373
+ };
374
+
375
+ // 手动更新曝光监听(该方法会在曝光插件加载时被重写)
376
+ updateImpression = () => {
377
+ consoleText(
378
+ '当前未集成半自动浏览插件,请集成插件后再调用 updateImpression!',
379
+ 'warn'
380
+ );
381
+ };
382
+
383
+ // 手动获取位置信息补发visit上报
384
+ setLocation = (latitude: number, longitude: number) => {
385
+ const nld = { latitude, longitude };
386
+ const ld = this.dataStore.locationData;
387
+ const verifyLT = (o: number) => o >= -180 && o <= 180;
388
+ if (
389
+ verifyLT(latitude) &&
390
+ verifyLT(longitude) &&
391
+ (ld.latitude !== latitude || ld.longitude !== longitude)
392
+ ) {
393
+ this.dataStore.locationData = nld;
394
+ }
395
+ };
396
+
397
+ // 获取打通信息
398
+ getGioInfo = () => {
399
+ const { uid, userId, userKey, sessionId } = this.userStore;
400
+ const {
401
+ projectId,
402
+ appId,
403
+ dataSourceId,
404
+ dataCollect,
405
+ idMapping,
406
+ extraParams,
407
+ ignoreFields
408
+ } = this.vdsConfig;
409
+ const infos: any = {
410
+ gioappid: appId,
411
+ giocs1: userId || '',
412
+ gioplatform: this.platformConfig.platform,
413
+ gioprojectid: projectId,
414
+ gios: sessionId,
415
+ giou: uid
416
+ };
417
+ infos.giodatacollect = dataCollect;
418
+ infos.giodatasourceid = dataSourceId;
419
+ if (idMapping) {
420
+ infos.giouserkey = userKey;
421
+ }
422
+ if (!isEmpty(extraParams)) {
423
+ extraParams.forEach((o) => {
424
+ if (!ignoreFields.includes(o)) {
425
+ infos[`gio${o}`] = this.dataStore.lastVisitEvent[o];
426
+ }
427
+ });
428
+ }
429
+ return qs.stringify(infos);
430
+ };
431
+ }
432
+
433
+ export default GrowingIO;
@@ -0,0 +1,152 @@
1
+ // @ts-nocheck
2
+ import { GrowingIOType } from '@@/types/growingIO';
3
+ import { PluginItem, PluginsType } from '@@/types/plugins';
4
+ import { isEmpty, isFunction, keys, lowerFirst, unset } from '@@/utils/glodash';
5
+ import { consoleText } from '@@/utils/tools';
6
+
7
+ import * as pluginsContext from '../pluginsIn/*.ts';
8
+
9
+ class Plugins implements PluginsType {
10
+ public pluginItems: PluginItem[];
11
+ constructor(public growingIO: GrowingIOType) {
12
+ this.pluginItems = [];
13
+ this.growingIO.emitter.on('onComposeBefore', this.onComposeBefore);
14
+ this.growingIO.emitter.on('onComposeAfter', this.onComposeAfter);
15
+ this.growingIO.emitter.on('onSendBefore', this.onSendBefore);
16
+ this.growingIO.emitter.on('onSendAfter', this.onSendAfter);
17
+ }
18
+
19
+ // 初始化内置插件,不允许客户自己热插拔的插件,内置打包完成
20
+ innerPluginInit = () => {
21
+ keys(pluginsContext.pluginsIn).forEach((key) => {
22
+ const { name, method }: { name: string; method: any } =
23
+ pluginsContext.pluginsIn[key];
24
+ // 若列表中出现同名插件,以第一个扫描出来的插件为准
25
+ const isExist = this.pluginItems.find((o) => o.name === name);
26
+ if (!isExist) {
27
+ this.pluginItems.push({
28
+ // 优先使用指定插件名
29
+ name: lowerFirst(name || key),
30
+ method: method ? method : (growingIO) => {} // eslint-disable-line
31
+ });
32
+ }
33
+ });
34
+ if (!isEmpty(this.pluginItems)) {
35
+ this.installAll();
36
+ }
37
+ };
38
+
39
+ // 挂载插件
40
+ install = (pluginName: string, pluginItem?: any, options?: any): boolean => {
41
+ const pluginTarget: PluginItem =
42
+ pluginItem ||
43
+ this.pluginItems.find((o: PluginItem) => o.name === pluginName);
44
+ // 插件已加载或与已加载的插件重名
45
+ if (this.growingIO?.plugins[pluginName]) {
46
+ consoleText(`重复加载插件 ${pluginName} 或插件重名,已跳过加载!`, 'warn');
47
+ return false;
48
+ }
49
+ // 插件列表中不存在要加载的插件
50
+ if (!pluginTarget) {
51
+ consoleText(`插件加载失败!不存在名为 ${pluginName} 的插件!`, 'error');
52
+ return false;
53
+ }
54
+ // 将插件实例挂载到growingIO实例上使得其他模块可以调用
55
+ try {
56
+ this.growingIO.plugins[pluginName] = new pluginTarget.method(
57
+ this.growingIO,
58
+ options
59
+ );
60
+ if (pluginItem) {
61
+ consoleText(`加载插件:${pluginName}`, 'info');
62
+ }
63
+ return true;
64
+ } catch (error) {
65
+ consoleText(`插件【${pluginName}】加载异常 ${error}`, 'error');
66
+ return false;
67
+ }
68
+ };
69
+
70
+ // 挂载所有插件
71
+ installAll = (plugins: PluginItem[]) => {
72
+ (plugins || this.pluginItems).forEach((o: PluginItem) =>
73
+ this.install(o.name, plugins ? o : undefined, o.options)
74
+ );
75
+ };
76
+
77
+ // 移除插件
78
+ uninstall = (pluginName: string): boolean => {
79
+ unset(this.pluginItems, pluginName);
80
+ const u = unset(this.growingIO?.plugins, pluginName);
81
+ if (!u) {
82
+ consoleText(`卸载插件 ${pluginName} 失败!`, 'error');
83
+ }
84
+ return u;
85
+ };
86
+
87
+ // 移除所有插件
88
+ uninstallAll = () => {
89
+ this.pluginItems.forEach((o: PluginItem) => this.uninstall(o.name));
90
+ };
91
+
92
+ lifeError = (p: PluginItem, e: any) =>
93
+ consoleText(`插件执行错误 ${p.name} ${e}`, 'error');
94
+
95
+ // 触发生命周期事件(事件合成前)
96
+ onComposeBefore = (args: any) => {
97
+ this.pluginItems.forEach((o: PluginItem) => {
98
+ const method = this.growingIO.plugins[o.name]?.onComposeBefore;
99
+ if (method && isFunction(method)) {
100
+ try {
101
+ method(args);
102
+ } catch (e) {
103
+ this.lifeError(o, e);
104
+ }
105
+ }
106
+ });
107
+ };
108
+
109
+ // 触发生命周期事件(事件合成后)
110
+ onComposeAfter = (args: any) => {
111
+ this.pluginItems.forEach((o: PluginItem) => {
112
+ const method = this.growingIO.plugins[o.name]?.onComposeAfter;
113
+ if (method && isFunction(method)) {
114
+ try {
115
+ method(args);
116
+ } catch (e) {
117
+ this.lifeError(o, e);
118
+ }
119
+ }
120
+ });
121
+ };
122
+
123
+ // 触发生命周期事件(事件发送前)
124
+ onSendBefore = (args: any) => {
125
+ this.pluginItems.forEach((o: PluginItem) => {
126
+ const method = this.growingIO.plugins[o.name]?.onSendBefore;
127
+ if (method && isFunction(method)) {
128
+ try {
129
+ method(args);
130
+ } catch (e) {
131
+ this.lifeError(o, e);
132
+ }
133
+ }
134
+ });
135
+ };
136
+
137
+ // 触发生命周期事件(事件发送后)
138
+ onSendAfter = (args: any) => {
139
+ this.pluginItems.forEach((o: PluginItem) => {
140
+ const method = this.growingIO.plugins[o.name]?.onSendAfter;
141
+ if (method && isFunction(method)) {
142
+ try {
143
+ method(args);
144
+ } catch (e) {
145
+ this.lifeError(o, e);
146
+ }
147
+ }
148
+ });
149
+ };
150
+ }
151
+
152
+ export default Plugins;