@gctrack/uni 0.1.1 → 0.2.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.
- package/dist/index.cjs +145 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +109 -17
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
package/dist/index.cjs
CHANGED
|
@@ -1,24 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
const __gctrack_core = __toESM(require("@gctrack/core"));
|
|
25
|
+
const __gctrack_protocol = __toESM(require("@gctrack/protocol"));
|
|
26
|
+
|
|
3
27
|
//#region src/index.ts
|
|
4
28
|
/** uni 适配实现 —— 全端用 uni.* 标准 API,不写 #ifdef */
|
|
5
29
|
const uniAdapter = {
|
|
6
30
|
getStorage: (k) => {
|
|
7
31
|
try {
|
|
8
32
|
return uni.getStorageSync(k);
|
|
9
|
-
} catch {
|
|
33
|
+
} catch (e) {
|
|
10
34
|
return null;
|
|
11
35
|
}
|
|
12
36
|
},
|
|
13
37
|
setStorage: (k, v) => {
|
|
14
38
|
try {
|
|
15
39
|
uni.setStorageSync(k, v);
|
|
16
|
-
} catch {}
|
|
40
|
+
} catch (e) {}
|
|
17
41
|
},
|
|
18
42
|
removeStorage: (k) => {
|
|
19
43
|
try {
|
|
20
44
|
uni.removeStorageSync(k);
|
|
21
|
-
} catch {}
|
|
45
|
+
} catch (e) {}
|
|
22
46
|
},
|
|
23
47
|
request: (opts) => new Promise((resolve, reject) => {
|
|
24
48
|
uni.request({
|
|
@@ -36,7 +60,7 @@ const uniAdapter = {
|
|
|
36
60
|
getSystemInfo: () => {
|
|
37
61
|
try {
|
|
38
62
|
return uni.getSystemInfoSync();
|
|
39
|
-
} catch {
|
|
63
|
+
} catch (e) {
|
|
40
64
|
return {};
|
|
41
65
|
}
|
|
42
66
|
},
|
|
@@ -52,7 +76,7 @@ const uniAdapter = {
|
|
|
52
76
|
url: "/" + route + (query ? "?" + query : ""),
|
|
53
77
|
title: ""
|
|
54
78
|
};
|
|
55
|
-
} catch {
|
|
79
|
+
} catch (e) {
|
|
56
80
|
return {
|
|
57
81
|
pathname: "",
|
|
58
82
|
url: "",
|
|
@@ -63,7 +87,7 @@ const uniAdapter = {
|
|
|
63
87
|
onUnload: (cb) => {
|
|
64
88
|
try {
|
|
65
89
|
uni.onAppHide && uni.onAppHide(cb);
|
|
66
|
-
} catch {}
|
|
90
|
+
} catch (e) {}
|
|
67
91
|
}
|
|
68
92
|
};
|
|
69
93
|
/**
|
|
@@ -87,45 +111,140 @@ function detectPlatform() {
|
|
|
87
111
|
const info = uni.getSystemInfoSync();
|
|
88
112
|
const p = info.uniPlatform || info.platform;
|
|
89
113
|
if (typeof p === "string") {
|
|
90
|
-
if (p.includes("mp-weixin") || p.includes("weixin")) return
|
|
91
|
-
if (p.includes("mp-alipay") || p.includes("alipay")) return
|
|
92
|
-
if (p.includes("mp-jd") || p.includes("jd")) return
|
|
93
|
-
if (p.includes("mp-xhs") || p.includes("xhs")) return
|
|
94
|
-
if (p.includes("mp-baidu") || p.includes("baidu")) return
|
|
95
|
-
if (p.includes("h5")) return
|
|
114
|
+
if (p.includes("mp-weixin") || p.includes("weixin")) return __gctrack_protocol.Platform.WeixinMp;
|
|
115
|
+
if (p.includes("mp-alipay") || p.includes("alipay")) return __gctrack_protocol.Platform.AlipayMp;
|
|
116
|
+
if (p.includes("mp-jd") || p.includes("jd")) return __gctrack_protocol.Platform.JdMp;
|
|
117
|
+
if (p.includes("mp-xhs") || p.includes("xhs")) return __gctrack_protocol.Platform.XhsMp;
|
|
118
|
+
if (p.includes("mp-baidu") || p.includes("baidu")) return __gctrack_protocol.Platform.BaiduMp;
|
|
119
|
+
if (p.includes("h5")) return __gctrack_protocol.Platform.H5;
|
|
96
120
|
}
|
|
97
|
-
} catch {}
|
|
98
|
-
return
|
|
121
|
+
} catch (e) {}
|
|
122
|
+
return __gctrack_protocol.Platform.WeixinMp;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`。
|
|
126
|
+
*/
|
|
127
|
+
function getComponentName(vm) {
|
|
128
|
+
if (!vm) return void 0;
|
|
129
|
+
const name = vm.$options && (vm.$options.name || vm.$options._componentTag) || vm.type && vm.type.name || vm.$ && vm.$.type && vm.$.type.name;
|
|
130
|
+
return name || void 0;
|
|
99
131
|
}
|
|
100
132
|
/**
|
|
101
|
-
*
|
|
102
|
-
* -
|
|
133
|
+
* 错误捕获一键挂载(Vue2/Vue3 通用):
|
|
134
|
+
* - appOrVue.config.errorHandler → vue_error
|
|
103
135
|
* - uni.onUnhandledRejection → promise_error
|
|
104
|
-
* App.onError 需在 App.vue 里手动调用 tracker.track
|
|
136
|
+
* App.onError 需在 App.vue 里手动调用 tracker.track(见 design.md 13.2)。
|
|
105
137
|
*/
|
|
106
|
-
function installErrorCapture(
|
|
107
|
-
if (
|
|
108
|
-
tracker.track(
|
|
138
|
+
function installErrorCapture(appOrVue, tracker) {
|
|
139
|
+
if (appOrVue && appOrVue.config) appOrVue.config.errorHandler = (err, vm, info) => {
|
|
140
|
+
tracker.track(__gctrack_protocol.EventType.VueError, {
|
|
109
141
|
message: err && err.message || String(err),
|
|
110
142
|
stack: err ? err.stack : void 0,
|
|
111
143
|
info,
|
|
112
|
-
componentName: vm
|
|
144
|
+
componentName: getComponentName(vm)
|
|
113
145
|
});
|
|
114
146
|
};
|
|
115
147
|
try {
|
|
116
148
|
uni.onUnhandledRejection && uni.onUnhandledRejection((res) => {
|
|
117
149
|
const reason = res ? res.reason : void 0;
|
|
118
|
-
tracker.track(
|
|
150
|
+
tracker.track(__gctrack_protocol.EventType.PromiseError, {
|
|
119
151
|
message: reason && reason.message || String(reason),
|
|
120
152
|
stack: reason ? reason.stack : void 0
|
|
121
153
|
});
|
|
122
154
|
});
|
|
123
|
-
} catch {}
|
|
155
|
+
} catch (e) {}
|
|
124
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* uni 端匿名访客 ID:走 uni storage(跨会话稳定),供 createTracker({ getVisitorId }) 注入。
|
|
159
|
+
*/
|
|
160
|
+
function getUniVisitorId() {
|
|
161
|
+
let id = uniAdapter.getStorage(__gctrack_core.VISITOR_ID_KEY);
|
|
162
|
+
if (!id || typeof id !== "string") {
|
|
163
|
+
id = (0, __gctrack_core.generateId)();
|
|
164
|
+
uniAdapter.setStorage(__gctrack_core.VISITOR_ID_KEY, id);
|
|
165
|
+
}
|
|
166
|
+
return id;
|
|
167
|
+
}
|
|
168
|
+
/** 小程序持久化待发事件键(与 core Web 版同名) */
|
|
169
|
+
const MP_PENDING_KEY = "__gctrack_pending_events__";
|
|
170
|
+
/**
|
|
171
|
+
* 小程序离线持久化适配器:走 uniAdapter storage(uni.getStorageSync/setStorageSync),
|
|
172
|
+
* 供 createTracker({ persistence: 'mp', persistenceAdapter: createMpPersistence() }) 注入。
|
|
173
|
+
*/
|
|
174
|
+
function createMpPersistence() {
|
|
175
|
+
return {
|
|
176
|
+
load() {
|
|
177
|
+
let events = [];
|
|
178
|
+
try {
|
|
179
|
+
const raw = uniAdapter.getStorage(MP_PENDING_KEY);
|
|
180
|
+
if (raw) {
|
|
181
|
+
events = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
182
|
+
uniAdapter.removeStorage(MP_PENDING_KEY);
|
|
183
|
+
}
|
|
184
|
+
} catch (e) {
|
|
185
|
+
events = [];
|
|
186
|
+
}
|
|
187
|
+
return Promise.resolve(events);
|
|
188
|
+
},
|
|
189
|
+
save(events) {
|
|
190
|
+
try {
|
|
191
|
+
uniAdapter.setStorage(MP_PENDING_KEY, JSON.stringify(events));
|
|
192
|
+
} catch (e) {}
|
|
193
|
+
return Promise.resolve();
|
|
194
|
+
},
|
|
195
|
+
clear() {
|
|
196
|
+
try {
|
|
197
|
+
uniAdapter.removeStorage(MP_PENDING_KEY);
|
|
198
|
+
} catch (e) {}
|
|
199
|
+
return Promise.resolve();
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* 小程序自动 PV:全局 mixin onShow,取 getCurrentPages() 栈顶 route+options 拼 pathname
|
|
205
|
+
* 上报 page_view,并显式写 event.pathname(小程序无 window.location,core autoCollect 取不到)。
|
|
206
|
+
*/
|
|
207
|
+
function installPageView(appOrVue, tracker) {
|
|
208
|
+
appOrVue.mixin({ onShow() {
|
|
209
|
+
const info = uniAdapter.getPageInfo();
|
|
210
|
+
tracker.track(__gctrack_protocol.EventType.PageView, { route: info.url }, {
|
|
211
|
+
pathname: info.pathname,
|
|
212
|
+
url: info.url,
|
|
213
|
+
title: info.title
|
|
214
|
+
});
|
|
215
|
+
} });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* GCTrack uni 插件对象(Vue2/Vue3 通用)。
|
|
219
|
+
* - 全局属性:V2 prototype / V3 globalProperties
|
|
220
|
+
* - 错误捕获:errorHandler(委托 installErrorCapture)
|
|
221
|
+
* - mixin:暴露 $track / $trackPageView
|
|
222
|
+
* - PV 采集:默认挂 installPageView(onShow)
|
|
223
|
+
*/
|
|
224
|
+
const uniPlugin = { install(appOrVue, options) {
|
|
225
|
+
const { tracker, trackPageView = true } = options;
|
|
226
|
+
const v2 = typeof appOrVue === "function";
|
|
227
|
+
if (v2) appOrVue.prototype.$tracker = tracker;
|
|
228
|
+
else appOrVue.config.globalProperties.$tracker = tracker;
|
|
229
|
+
installErrorCapture(appOrVue, tracker);
|
|
230
|
+
appOrVue.mixin({ methods: {
|
|
231
|
+
$track(eventType, data) {
|
|
232
|
+
if (this.$tracker) this.$tracker.track(eventType, data);
|
|
233
|
+
},
|
|
234
|
+
$trackPageView(data) {
|
|
235
|
+
if (this.$tracker) this.$tracker.track(__gctrack_protocol.EventType.PageView, data);
|
|
236
|
+
}
|
|
237
|
+
} });
|
|
238
|
+
if (trackPageView) installPageView(appOrVue, tracker);
|
|
239
|
+
} };
|
|
240
|
+
|
|
125
241
|
//#endregion
|
|
242
|
+
exports.createMpPersistence = createMpPersistence;
|
|
126
243
|
exports.createUniSendFn = createUniSendFn;
|
|
127
244
|
exports.detectPlatform = detectPlatform;
|
|
245
|
+
exports.getUniVisitorId = getUniVisitorId;
|
|
128
246
|
exports.installErrorCapture = installErrorCapture;
|
|
247
|
+
exports.installPageView = installPageView;
|
|
129
248
|
exports.uniAdapter = uniAdapter;
|
|
130
|
-
|
|
249
|
+
exports.uniPlugin = uniPlugin;
|
|
131
250
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Platform","EventType"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/uni —— 小程序多端适配\n *\n * 小程序无 window/document/navigator/sendBeacon/fetch/PerformanceObserver,\n * 本包提供 PlatformAdapter(存储/网络/生命周期/设备/页面)的 uni 实现,\n * 以及错误捕获(App.onError / unhandledRejection / Vue.errorHandler)一键挂载。\n *\n * 详见 design.md 5.5。完整实现(PV、点击、白屏耗时等)在「@gctrack/uni 完善」阶段补充。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { EventType, Platform } from '@gctrack/protocol'\n\n// 小程序运行时注入的全局(各端一致提供 uni / getCurrentPages)\ndeclare const uni: any\ndeclare function getCurrentPages(): any[]\n\n/** 平台适配器接口 —— core 通过它解耦浏览器 API,详见 design.md 5.5 */\nexport interface PlatformAdapter {\n getStorage(key: string): any\n setStorage(key: string, value: any): void\n removeStorage(key: string): void\n request(opts: {\n url: string\n method?: string\n data?: any\n header?: Record<string, string>\n }): Promise<{ statusCode: number; data: any }>\n getSystemInfo(): Record<string, any>\n getPageInfo(): { pathname: string; url: string; title: string }\n onUnload(cb: () => void): void\n}\n\n/** uni 适配实现 —— 全端用 uni.* 标准 API,不写 #ifdef */\nexport const uniAdapter: PlatformAdapter = {\n getStorage: (k) => {\n try {\n return uni.getStorageSync(k)\n } catch {\n return null\n }\n },\n setStorage: (k, v) => {\n try {\n uni.setStorageSync(k, v)\n } catch {\n /* ignore */\n }\n },\n removeStorage: (k) => {\n try {\n uni.removeStorageSync(k)\n } catch {\n /* ignore */\n }\n },\n request: (opts) =>\n new Promise((resolve, reject) => {\n uni.request({\n url: opts.url,\n method: (opts.method || 'POST') as any,\n data: opts.data,\n header: opts.header || {},\n success: (res: any) => resolve({ statusCode: res.statusCode, data: res.data }),\n fail: (err: any) => reject(err),\n })\n }),\n getSystemInfo: () => {\n try {\n return uni.getSystemInfoSync()\n } catch {\n return {}\n }\n },\n getPageInfo: () => {\n try {\n const pages = getCurrentPages()\n const top = pages[pages.length - 1]\n const route: string = (top && top.route) || ''\n const options = (top && top.options) || {}\n const query = Object.keys(options)\n .map((k) => `${k}=${options[k]}`)\n .join('&')\n return {\n pathname: '/' + route,\n url: '/' + route + (query ? '?' + query : ''),\n title: '',\n }\n } catch {\n return { pathname: '', url: '', title: '' }\n }\n },\n onUnload: (cb) => {\n // 兜底:App.onHide / Page.onHide 由 installAppLifecycle 接管,这里注册 uni 级监听\n try {\n uni.onAppHide && uni.onAppHide(cb)\n } catch {\n /* ignore */\n }\n },\n}\n\n/**\n * 构造基于 uni.request 的 sendFn,供 createTracker({ sendFn }) 使用。\n * 小程序无 sendBeacon/fetch,统一走 uni.request;header 值强制 String()(XHS 要求)。\n */\nexport function createUniSendFn(reportUrl: string, appKey?: string) {\n return (events: any[]): Promise<void> =>\n uniAdapter\n .request({\n url: reportUrl,\n method: 'POST',\n data: events,\n header: {\n 'content-type': 'application/json',\n 'X-App-Key': appKey ? String(appKey) : '',\n },\n })\n .then(() => undefined)\n}\n\n/** 根据 uni 运行环境推断 Platform 标识(写入 context.platform) */\nexport function detectPlatform(): string {\n try {\n const info = uni.getSystemInfoSync()\n // uni-app 注入 UNI_PLATFORM / uniPlatform\n const p = info.uniPlatform || info.platform\n if (typeof p === 'string') {\n if (p.includes('mp-weixin') || p.includes('weixin')) return Platform.WeixinMp\n if (p.includes('mp-alipay') || p.includes('alipay')) return Platform.AlipayMp\n if (p.includes('mp-jd') || p.includes('jd')) return Platform.JdMp\n if (p.includes('mp-xhs') || p.includes('xhs')) return Platform.XhsMp\n if (p.includes('mp-baidu') || p.includes('baidu')) return Platform.BaiduMp\n if (p.includes('h5')) return Platform.H5\n }\n } catch {\n /* ignore */\n }\n return Platform.WeixinMp\n}\n\n/**\n * 错误捕获一键挂载:\n * - Vue.config.errorHandler → vue_error\n * - uni.onUnhandledRejection → promise_error\n * App.onError 需在 App.vue 里手动调用 tracker.track(见 design.md 13.2)。\n */\nexport function installErrorCapture(Vue: any, tracker: Tracker): void {\n if (Vue && Vue.config) {\n Vue.config.errorHandler = (err: any, vm: any, info: string) => {\n tracker.track(EventType.VueError, {\n message: (err && err.message) || String(err),\n stack: err ? err.stack : undefined,\n info,\n componentName: vm && vm.$options ? (vm.$options.name || vm.$options._componentTag) : undefined,\n })\n }\n }\n try {\n uni.onUnhandledRejection &&\n uni.onUnhandledRejection((res: any) => {\n const reason = res ? res.reason : undefined\n tracker.track(EventType.PromiseError, {\n message: (reason && reason.message) || String(reason),\n stack: reason ? reason.stack : undefined,\n })\n })\n } catch {\n /* ignore */\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["uniAdapter: PlatformAdapter","res: any","err: any","route: string","reportUrl: string","appKey?: string","events: any[]","Platform","vm: any","appOrVue: any","tracker: Tracker","info: string","EventType","VISITOR_ID_KEY","events: EventData[]","options: UniPluginOptions","eventType: string","data?: Record<string, any>"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/uni —— 小程序多端适配\n *\n * 小程序无 window/document/navigator/sendBeacon/fetch/PerformanceObserver,\n * 本包提供 PlatformAdapter(存储/网络/生命周期/设备/页面)的 uni 实现,\n * 以及错误捕获(App.onError / unhandledRejection / Vue.errorHandler)一键挂载。\n *\n * 详见 design.md 5.5。完整实现(PV、点击、白屏耗时等)在「@gctrack/uni 完善」阶段补充。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { generateId, VISITOR_ID_KEY } from '@gctrack/core'\nimport { EventType, Platform } from '@gctrack/protocol'\nimport type { EventData, PersistenceAdapter } from '@gctrack/protocol'\n\n// 小程序运行时注入的全局(各端一致提供 uni / getCurrentPages)\ndeclare const uni: any\ndeclare function getCurrentPages(): any[]\n\n/** 平台适配器接口 —— core 通过它解耦浏览器 API,详见 design.md 5.5 */\nexport interface PlatformAdapter {\n getStorage(key: string): any\n setStorage(key: string, value: any): void\n removeStorage(key: string): void\n request(opts: {\n url: string\n method?: string\n data?: any\n header?: Record<string, string>\n }): Promise<{ statusCode: number; data: any }>\n getSystemInfo(): Record<string, any>\n getPageInfo(): { pathname: string; url: string; title: string }\n onUnload(cb: () => void): void\n}\n\n/** uni 适配实现 —— 全端用 uni.* 标准 API,不写 #ifdef */\nexport const uniAdapter: PlatformAdapter = {\n getStorage: (k) => {\n try {\n return uni.getStorageSync(k)\n } catch (e) {\n return null\n }\n },\n setStorage: (k, v) => {\n try {\n uni.setStorageSync(k, v)\n } catch (e) {\n /* ignore */\n }\n },\n removeStorage: (k) => {\n try {\n uni.removeStorageSync(k)\n } catch (e) {\n /* ignore */\n }\n },\n request: (opts) =>\n new Promise((resolve, reject) => {\n uni.request({\n url: opts.url,\n method: (opts.method || 'POST') as any,\n data: opts.data,\n header: opts.header || {},\n success: (res: any) => resolve({ statusCode: res.statusCode, data: res.data }),\n fail: (err: any) => reject(err),\n })\n }),\n getSystemInfo: () => {\n try {\n return uni.getSystemInfoSync()\n } catch (e) {\n return {}\n }\n },\n getPageInfo: () => {\n try {\n const pages = getCurrentPages()\n const top = pages[pages.length - 1]\n const route: string = (top && top.route) || ''\n const options = (top && top.options) || {}\n const query = Object.keys(options)\n .map((k) => `${k}=${options[k]}`)\n .join('&')\n return {\n pathname: '/' + route,\n url: '/' + route + (query ? '?' + query : ''),\n title: '',\n }\n } catch (e) {\n return { pathname: '', url: '', title: '' }\n }\n },\n onUnload: (cb) => {\n // 兜底:App.onHide / Page.onHide 由 installAppLifecycle 接管,这里注册 uni 级监听\n try {\n uni.onAppHide && uni.onAppHide(cb)\n } catch (e) {\n /* ignore */\n }\n },\n}\n\n/**\n * 构造基于 uni.request 的 sendFn,供 createTracker({ sendFn }) 使用。\n * 小程序无 sendBeacon/fetch,统一走 uni.request;header 值强制 String()(XHS 要求)。\n */\nexport function createUniSendFn(reportUrl: string, appKey?: string) {\n return (events: any[]): Promise<void> =>\n uniAdapter\n .request({\n url: reportUrl,\n method: 'POST',\n data: events,\n header: {\n 'content-type': 'application/json',\n 'X-App-Key': appKey ? String(appKey) : '',\n },\n })\n .then(() => undefined)\n}\n\n/** 根据 uni 运行环境推断 Platform 标识(写入 context.platform) */\nexport function detectPlatform(): string {\n try {\n const info = uni.getSystemInfoSync()\n // uni-app 注入 UNI_PLATFORM / uniPlatform\n const p = info.uniPlatform || info.platform\n if (typeof p === 'string') {\n if (p.includes('mp-weixin') || p.includes('weixin')) return Platform.WeixinMp\n if (p.includes('mp-alipay') || p.includes('alipay')) return Platform.AlipayMp\n if (p.includes('mp-jd') || p.includes('jd')) return Platform.JdMp\n if (p.includes('mp-xhs') || p.includes('xhs')) return Platform.XhsMp\n if (p.includes('mp-baidu') || p.includes('baidu')) return Platform.BaiduMp\n if (p.includes('h5')) return Platform.H5\n }\n } catch (e) {\n /* ignore */\n }\n return Platform.WeixinMp\n}\n\n/**\n * 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`。\n */\nfunction getComponentName(vm: any): string | undefined {\n if (!vm) return undefined\n const name =\n (vm.$options && (vm.$options.name || vm.$options._componentTag)) ||\n (vm.type && vm.type.name) ||\n (vm.$ && vm.$.type && vm.$.type.name)\n return name || undefined\n}\n\n/**\n * 错误捕获一键挂载(Vue2/Vue3 通用):\n * - appOrVue.config.errorHandler → vue_error\n * - uni.onUnhandledRejection → promise_error\n * App.onError 需在 App.vue 里手动调用 tracker.track(见 design.md 13.2)。\n */\nexport function installErrorCapture(appOrVue: any, tracker: Tracker): void {\n if (appOrVue && appOrVue.config) {\n appOrVue.config.errorHandler = (err: any, vm: any, info: string) => {\n tracker.track(EventType.VueError, {\n message: (err && err.message) || String(err),\n stack: err ? err.stack : undefined,\n info,\n componentName: getComponentName(vm),\n })\n }\n }\n try {\n uni.onUnhandledRejection &&\n uni.onUnhandledRejection((res: any) => {\n const reason = res ? res.reason : undefined\n tracker.track(EventType.PromiseError, {\n message: (reason && reason.message) || String(reason),\n stack: reason ? reason.stack : undefined,\n })\n })\n } catch (e) {\n /* ignore */\n }\n}\n\n/**\n * uni 端匿名访客 ID:走 uni storage(跨会话稳定),供 createTracker({ getVisitorId }) 注入。\n */\nexport function getUniVisitorId(): string {\n let id = uniAdapter.getStorage(VISITOR_ID_KEY)\n if (!id || typeof id !== 'string') {\n id = generateId()\n uniAdapter.setStorage(VISITOR_ID_KEY, id)\n }\n return id\n}\n\n/** 小程序持久化待发事件键(与 core Web 版同名) */\nconst MP_PENDING_KEY = '__gctrack_pending_events__'\n\n/**\n * 小程序离线持久化适配器:走 uniAdapter storage(uni.getStorageSync/setStorageSync),\n * 供 createTracker({ persistence: 'mp', persistenceAdapter: createMpPersistence() }) 注入。\n */\nexport function createMpPersistence(): PersistenceAdapter {\n return {\n load(): Promise<EventData[]> {\n let events: EventData[] = []\n try {\n const raw = uniAdapter.getStorage(MP_PENDING_KEY)\n if (raw) {\n events = (typeof raw === 'string' ? JSON.parse(raw) : raw) as EventData[]\n uniAdapter.removeStorage(MP_PENDING_KEY)\n }\n } catch (e) {\n events = []\n }\n return Promise.resolve(events)\n },\n save(events: EventData[]): Promise<void> {\n try {\n uniAdapter.setStorage(MP_PENDING_KEY, JSON.stringify(events))\n } catch (e) {\n /* ignore */\n }\n return Promise.resolve()\n },\n clear(): Promise<void> {\n try {\n uniAdapter.removeStorage(MP_PENDING_KEY)\n } catch (e) {\n /* ignore */\n }\n return Promise.resolve()\n },\n }\n}\n\n/**\n * 小程序自动 PV:全局 mixin onShow,取 getCurrentPages() 栈顶 route+options 拼 pathname\n * 上报 page_view,并显式写 event.pathname(小程序无 window.location,core autoCollect 取不到)。\n */\nexport function installPageView(appOrVue: any, tracker: Tracker): void {\n appOrVue.mixin({\n onShow(this: any) {\n const info = uniAdapter.getPageInfo()\n tracker.track(\n EventType.PageView,\n { route: info.url },\n { pathname: info.pathname, url: info.url, title: info.title },\n )\n },\n })\n}\n\n/**\n * uni 插件选项\n */\nexport interface UniPluginOptions {\n tracker: Tracker\n /** 是否自动采集 PV(默认 true,挂全局 onShow mixin) */\n trackPageView?: boolean\n}\n\n/**\n * GCTrack uni 插件对象(Vue2/Vue3 通用)。\n * - 全局属性:V2 prototype / V3 globalProperties\n * - 错误捕获:errorHandler(委托 installErrorCapture)\n * - mixin:暴露 $track / $trackPageView\n * - PV 采集:默认挂 installPageView(onShow)\n */\nexport const uniPlugin = {\n install(appOrVue: any, options: UniPluginOptions): void {\n const { tracker, trackPageView = true } = options\n const v2 = typeof appOrVue === 'function'\n\n if (v2) {\n appOrVue.prototype.$tracker = tracker\n } else {\n appOrVue.config.globalProperties.$tracker = tracker\n }\n\n installErrorCapture(appOrVue, tracker)\n\n // Vue2/3 都有 .mixin\n appOrVue.mixin({\n methods: {\n $track(this: any, eventType: string, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(eventType, data)\n }\n },\n $trackPageView(this: any, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(EventType.PageView, data)\n }\n },\n },\n })\n\n if (trackPageView) {\n installPageView(appOrVue, tracker)\n }\n },\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Tracker } from "@gctrack/core";
|
|
2
|
+
import type { PersistenceAdapter } from "@gctrack/protocol";
|
|
2
3
|
export interface PlatformAdapter {
|
|
3
4
|
getStorage(key: string): any;
|
|
4
5
|
setStorage(key: string, value: any): void;
|
|
@@ -23,4 +24,12 @@ export interface PlatformAdapter {
|
|
|
23
24
|
export declare const uniAdapter: PlatformAdapter;
|
|
24
25
|
export declare function createUniSendFn(reportUrl: string, appKey?: string): (events: any[]) => Promise<void>;
|
|
25
26
|
export declare function detectPlatform(): string;
|
|
26
|
-
export declare function installErrorCapture(
|
|
27
|
+
export declare function installErrorCapture(appOrVue: any, tracker: Tracker): void;
|
|
28
|
+
export declare function getUniVisitorId(): string;
|
|
29
|
+
export declare function createMpPersistence(): PersistenceAdapter;
|
|
30
|
+
export declare function installPageView(appOrVue: any, tracker: Tracker): void;
|
|
31
|
+
export interface UniPluginOptions {
|
|
32
|
+
tracker: Tracker;
|
|
33
|
+
trackPageView?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare const uniPlugin: {install(appOrVue: any, options: UniPluginOptions): void};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Tracker } from "@gctrack/core";
|
|
2
|
+
import type { PersistenceAdapter } from "@gctrack/protocol";
|
|
2
3
|
export interface PlatformAdapter {
|
|
3
4
|
getStorage(key: string): any;
|
|
4
5
|
setStorage(key: string, value: any): void;
|
|
@@ -23,4 +24,12 @@ export interface PlatformAdapter {
|
|
|
23
24
|
export declare const uniAdapter: PlatformAdapter;
|
|
24
25
|
export declare function createUniSendFn(reportUrl: string, appKey?: string): (events: any[]) => Promise<void>;
|
|
25
26
|
export declare function detectPlatform(): string;
|
|
26
|
-
export declare function installErrorCapture(
|
|
27
|
+
export declare function installErrorCapture(appOrVue: any, tracker: Tracker): void;
|
|
28
|
+
export declare function getUniVisitorId(): string;
|
|
29
|
+
export declare function createMpPersistence(): PersistenceAdapter;
|
|
30
|
+
export declare function installPageView(appOrVue: any, tracker: Tracker): void;
|
|
31
|
+
export interface UniPluginOptions {
|
|
32
|
+
tracker: Tracker;
|
|
33
|
+
trackPageView?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export declare const uniPlugin: {install(appOrVue: any, options: UniPluginOptions): void};
|
package/dist/index.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import "
|
|
1
|
+
import { VISITOR_ID_KEY, generateId } from "@gctrack/core";
|
|
2
2
|
import { EventType, Platform } from "@gctrack/protocol";
|
|
3
|
+
|
|
3
4
|
//#region src/index.ts
|
|
4
5
|
/** uni 适配实现 —— 全端用 uni.* 标准 API,不写 #ifdef */
|
|
5
6
|
const uniAdapter = {
|
|
6
7
|
getStorage: (k) => {
|
|
7
8
|
try {
|
|
8
9
|
return uni.getStorageSync(k);
|
|
9
|
-
} catch {
|
|
10
|
+
} catch (e) {
|
|
10
11
|
return null;
|
|
11
12
|
}
|
|
12
13
|
},
|
|
13
14
|
setStorage: (k, v) => {
|
|
14
15
|
try {
|
|
15
16
|
uni.setStorageSync(k, v);
|
|
16
|
-
} catch {}
|
|
17
|
+
} catch (e) {}
|
|
17
18
|
},
|
|
18
19
|
removeStorage: (k) => {
|
|
19
20
|
try {
|
|
20
21
|
uni.removeStorageSync(k);
|
|
21
|
-
} catch {}
|
|
22
|
+
} catch (e) {}
|
|
22
23
|
},
|
|
23
24
|
request: (opts) => new Promise((resolve, reject) => {
|
|
24
25
|
uni.request({
|
|
@@ -36,7 +37,7 @@ const uniAdapter = {
|
|
|
36
37
|
getSystemInfo: () => {
|
|
37
38
|
try {
|
|
38
39
|
return uni.getSystemInfoSync();
|
|
39
|
-
} catch {
|
|
40
|
+
} catch (e) {
|
|
40
41
|
return {};
|
|
41
42
|
}
|
|
42
43
|
},
|
|
@@ -52,7 +53,7 @@ const uniAdapter = {
|
|
|
52
53
|
url: "/" + route + (query ? "?" + query : ""),
|
|
53
54
|
title: ""
|
|
54
55
|
};
|
|
55
|
-
} catch {
|
|
56
|
+
} catch (e) {
|
|
56
57
|
return {
|
|
57
58
|
pathname: "",
|
|
58
59
|
url: "",
|
|
@@ -63,7 +64,7 @@ const uniAdapter = {
|
|
|
63
64
|
onUnload: (cb) => {
|
|
64
65
|
try {
|
|
65
66
|
uni.onAppHide && uni.onAppHide(cb);
|
|
66
|
-
} catch {}
|
|
67
|
+
} catch (e) {}
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
70
|
/**
|
|
@@ -94,22 +95,30 @@ function detectPlatform() {
|
|
|
94
95
|
if (p.includes("mp-baidu") || p.includes("baidu")) return Platform.BaiduMp;
|
|
95
96
|
if (p.includes("h5")) return Platform.H5;
|
|
96
97
|
}
|
|
97
|
-
} catch {}
|
|
98
|
+
} catch (e) {}
|
|
98
99
|
return Platform.WeixinMp;
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
|
-
*
|
|
102
|
-
|
|
102
|
+
* 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`。
|
|
103
|
+
*/
|
|
104
|
+
function getComponentName(vm) {
|
|
105
|
+
if (!vm) return void 0;
|
|
106
|
+
const name = vm.$options && (vm.$options.name || vm.$options._componentTag) || vm.type && vm.type.name || vm.$ && vm.$.type && vm.$.type.name;
|
|
107
|
+
return name || void 0;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 错误捕获一键挂载(Vue2/Vue3 通用):
|
|
111
|
+
* - appOrVue.config.errorHandler → vue_error
|
|
103
112
|
* - uni.onUnhandledRejection → promise_error
|
|
104
|
-
* App.onError 需在 App.vue 里手动调用 tracker.track
|
|
113
|
+
* App.onError 需在 App.vue 里手动调用 tracker.track(见 design.md 13.2)。
|
|
105
114
|
*/
|
|
106
|
-
function installErrorCapture(
|
|
107
|
-
if (
|
|
115
|
+
function installErrorCapture(appOrVue, tracker) {
|
|
116
|
+
if (appOrVue && appOrVue.config) appOrVue.config.errorHandler = (err, vm, info) => {
|
|
108
117
|
tracker.track(EventType.VueError, {
|
|
109
118
|
message: err && err.message || String(err),
|
|
110
119
|
stack: err ? err.stack : void 0,
|
|
111
120
|
info,
|
|
112
|
-
componentName: vm
|
|
121
|
+
componentName: getComponentName(vm)
|
|
113
122
|
});
|
|
114
123
|
};
|
|
115
124
|
try {
|
|
@@ -120,9 +129,92 @@ function installErrorCapture(Vue, tracker) {
|
|
|
120
129
|
stack: reason ? reason.stack : void 0
|
|
121
130
|
});
|
|
122
131
|
});
|
|
123
|
-
} catch {}
|
|
132
|
+
} catch (e) {}
|
|
124
133
|
}
|
|
125
|
-
|
|
126
|
-
|
|
134
|
+
/**
|
|
135
|
+
* uni 端匿名访客 ID:走 uni storage(跨会话稳定),供 createTracker({ getVisitorId }) 注入。
|
|
136
|
+
*/
|
|
137
|
+
function getUniVisitorId() {
|
|
138
|
+
let id = uniAdapter.getStorage(VISITOR_ID_KEY);
|
|
139
|
+
if (!id || typeof id !== "string") {
|
|
140
|
+
id = generateId();
|
|
141
|
+
uniAdapter.setStorage(VISITOR_ID_KEY, id);
|
|
142
|
+
}
|
|
143
|
+
return id;
|
|
144
|
+
}
|
|
145
|
+
/** 小程序持久化待发事件键(与 core Web 版同名) */
|
|
146
|
+
const MP_PENDING_KEY = "__gctrack_pending_events__";
|
|
147
|
+
/**
|
|
148
|
+
* 小程序离线持久化适配器:走 uniAdapter storage(uni.getStorageSync/setStorageSync),
|
|
149
|
+
* 供 createTracker({ persistence: 'mp', persistenceAdapter: createMpPersistence() }) 注入。
|
|
150
|
+
*/
|
|
151
|
+
function createMpPersistence() {
|
|
152
|
+
return {
|
|
153
|
+
load() {
|
|
154
|
+
let events = [];
|
|
155
|
+
try {
|
|
156
|
+
const raw = uniAdapter.getStorage(MP_PENDING_KEY);
|
|
157
|
+
if (raw) {
|
|
158
|
+
events = typeof raw === "string" ? JSON.parse(raw) : raw;
|
|
159
|
+
uniAdapter.removeStorage(MP_PENDING_KEY);
|
|
160
|
+
}
|
|
161
|
+
} catch (e) {
|
|
162
|
+
events = [];
|
|
163
|
+
}
|
|
164
|
+
return Promise.resolve(events);
|
|
165
|
+
},
|
|
166
|
+
save(events) {
|
|
167
|
+
try {
|
|
168
|
+
uniAdapter.setStorage(MP_PENDING_KEY, JSON.stringify(events));
|
|
169
|
+
} catch (e) {}
|
|
170
|
+
return Promise.resolve();
|
|
171
|
+
},
|
|
172
|
+
clear() {
|
|
173
|
+
try {
|
|
174
|
+
uniAdapter.removeStorage(MP_PENDING_KEY);
|
|
175
|
+
} catch (e) {}
|
|
176
|
+
return Promise.resolve();
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 小程序自动 PV:全局 mixin onShow,取 getCurrentPages() 栈顶 route+options 拼 pathname
|
|
182
|
+
* 上报 page_view,并显式写 event.pathname(小程序无 window.location,core autoCollect 取不到)。
|
|
183
|
+
*/
|
|
184
|
+
function installPageView(appOrVue, tracker) {
|
|
185
|
+
appOrVue.mixin({ onShow() {
|
|
186
|
+
const info = uniAdapter.getPageInfo();
|
|
187
|
+
tracker.track(EventType.PageView, { route: info.url }, {
|
|
188
|
+
pathname: info.pathname,
|
|
189
|
+
url: info.url,
|
|
190
|
+
title: info.title
|
|
191
|
+
});
|
|
192
|
+
} });
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* GCTrack uni 插件对象(Vue2/Vue3 通用)。
|
|
196
|
+
* - 全局属性:V2 prototype / V3 globalProperties
|
|
197
|
+
* - 错误捕获:errorHandler(委托 installErrorCapture)
|
|
198
|
+
* - mixin:暴露 $track / $trackPageView
|
|
199
|
+
* - PV 采集:默认挂 installPageView(onShow)
|
|
200
|
+
*/
|
|
201
|
+
const uniPlugin = { install(appOrVue, options) {
|
|
202
|
+
const { tracker, trackPageView = true } = options;
|
|
203
|
+
const v2 = typeof appOrVue === "function";
|
|
204
|
+
if (v2) appOrVue.prototype.$tracker = tracker;
|
|
205
|
+
else appOrVue.config.globalProperties.$tracker = tracker;
|
|
206
|
+
installErrorCapture(appOrVue, tracker);
|
|
207
|
+
appOrVue.mixin({ methods: {
|
|
208
|
+
$track(eventType, data) {
|
|
209
|
+
if (this.$tracker) this.$tracker.track(eventType, data);
|
|
210
|
+
},
|
|
211
|
+
$trackPageView(data) {
|
|
212
|
+
if (this.$tracker) this.$tracker.track(EventType.PageView, data);
|
|
213
|
+
}
|
|
214
|
+
} });
|
|
215
|
+
if (trackPageView) installPageView(appOrVue, tracker);
|
|
216
|
+
} };
|
|
127
217
|
|
|
218
|
+
//#endregion
|
|
219
|
+
export { createMpPersistence, createUniSendFn, detectPlatform, getUniVisitorId, installErrorCapture, installPageView, uniAdapter, uniPlugin };
|
|
128
220
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/uni —— 小程序多端适配\n *\n * 小程序无 window/document/navigator/sendBeacon/fetch/PerformanceObserver,\n * 本包提供 PlatformAdapter(存储/网络/生命周期/设备/页面)的 uni 实现,\n * 以及错误捕获(App.onError / unhandledRejection / Vue.errorHandler)一键挂载。\n *\n * 详见 design.md 5.5。完整实现(PV、点击、白屏耗时等)在「@gctrack/uni 完善」阶段补充。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { EventType, Platform } from '@gctrack/protocol'\n\n// 小程序运行时注入的全局(各端一致提供 uni / getCurrentPages)\ndeclare const uni: any\ndeclare function getCurrentPages(): any[]\n\n/** 平台适配器接口 —— core 通过它解耦浏览器 API,详见 design.md 5.5 */\nexport interface PlatformAdapter {\n getStorage(key: string): any\n setStorage(key: string, value: any): void\n removeStorage(key: string): void\n request(opts: {\n url: string\n method?: string\n data?: any\n header?: Record<string, string>\n }): Promise<{ statusCode: number; data: any }>\n getSystemInfo(): Record<string, any>\n getPageInfo(): { pathname: string; url: string; title: string }\n onUnload(cb: () => void): void\n}\n\n/** uni 适配实现 —— 全端用 uni.* 标准 API,不写 #ifdef */\nexport const uniAdapter: PlatformAdapter = {\n getStorage: (k) => {\n try {\n return uni.getStorageSync(k)\n } catch {\n return null\n }\n },\n setStorage: (k, v) => {\n try {\n uni.setStorageSync(k, v)\n } catch {\n /* ignore */\n }\n },\n removeStorage: (k) => {\n try {\n uni.removeStorageSync(k)\n } catch {\n /* ignore */\n }\n },\n request: (opts) =>\n new Promise((resolve, reject) => {\n uni.request({\n url: opts.url,\n method: (opts.method || 'POST') as any,\n data: opts.data,\n header: opts.header || {},\n success: (res: any) => resolve({ statusCode: res.statusCode, data: res.data }),\n fail: (err: any) => reject(err),\n })\n }),\n getSystemInfo: () => {\n try {\n return uni.getSystemInfoSync()\n } catch {\n return {}\n }\n },\n getPageInfo: () => {\n try {\n const pages = getCurrentPages()\n const top = pages[pages.length - 1]\n const route: string = (top && top.route) || ''\n const options = (top && top.options) || {}\n const query = Object.keys(options)\n .map((k) => `${k}=${options[k]}`)\n .join('&')\n return {\n pathname: '/' + route,\n url: '/' + route + (query ? '?' + query : ''),\n title: '',\n }\n } catch {\n return { pathname: '', url: '', title: '' }\n }\n },\n onUnload: (cb) => {\n // 兜底:App.onHide / Page.onHide 由 installAppLifecycle 接管,这里注册 uni 级监听\n try {\n uni.onAppHide && uni.onAppHide(cb)\n } catch {\n /* ignore */\n }\n },\n}\n\n/**\n * 构造基于 uni.request 的 sendFn,供 createTracker({ sendFn }) 使用。\n * 小程序无 sendBeacon/fetch,统一走 uni.request;header 值强制 String()(XHS 要求)。\n */\nexport function createUniSendFn(reportUrl: string, appKey?: string) {\n return (events: any[]): Promise<void> =>\n uniAdapter\n .request({\n url: reportUrl,\n method: 'POST',\n data: events,\n header: {\n 'content-type': 'application/json',\n 'X-App-Key': appKey ? String(appKey) : '',\n },\n })\n .then(() => undefined)\n}\n\n/** 根据 uni 运行环境推断 Platform 标识(写入 context.platform) */\nexport function detectPlatform(): string {\n try {\n const info = uni.getSystemInfoSync()\n // uni-app 注入 UNI_PLATFORM / uniPlatform\n const p = info.uniPlatform || info.platform\n if (typeof p === 'string') {\n if (p.includes('mp-weixin') || p.includes('weixin')) return Platform.WeixinMp\n if (p.includes('mp-alipay') || p.includes('alipay')) return Platform.AlipayMp\n if (p.includes('mp-jd') || p.includes('jd')) return Platform.JdMp\n if (p.includes('mp-xhs') || p.includes('xhs')) return Platform.XhsMp\n if (p.includes('mp-baidu') || p.includes('baidu')) return Platform.BaiduMp\n if (p.includes('h5')) return Platform.H5\n }\n } catch {\n /* ignore */\n }\n return Platform.WeixinMp\n}\n\n/**\n * 错误捕获一键挂载:\n * - Vue.config.errorHandler → vue_error\n * - uni.onUnhandledRejection → promise_error\n * App.onError 需在 App.vue 里手动调用 tracker.track(见 design.md 13.2)。\n */\nexport function installErrorCapture(Vue: any, tracker: Tracker): void {\n if (Vue && Vue.config) {\n Vue.config.errorHandler = (err: any, vm: any, info: string) => {\n tracker.track(EventType.VueError, {\n message: (err && err.message) || String(err),\n stack: err ? err.stack : undefined,\n info,\n componentName: vm && vm.$options ? (vm.$options.name || vm.$options._componentTag) : undefined,\n })\n }\n }\n try {\n uni.onUnhandledRejection &&\n uni.onUnhandledRejection((res: any) => {\n const reason = res ? res.reason : undefined\n tracker.track(EventType.PromiseError, {\n message: (reason && reason.message) || String(reason),\n stack: reason ? reason.stack : undefined,\n })\n })\n } catch {\n /* ignore */\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["uniAdapter: PlatformAdapter","res: any","err: any","route: string","reportUrl: string","appKey?: string","events: any[]","vm: any","appOrVue: any","tracker: Tracker","info: string","events: EventData[]","options: UniPluginOptions","eventType: string","data?: Record<string, any>"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/uni —— 小程序多端适配\n *\n * 小程序无 window/document/navigator/sendBeacon/fetch/PerformanceObserver,\n * 本包提供 PlatformAdapter(存储/网络/生命周期/设备/页面)的 uni 实现,\n * 以及错误捕获(App.onError / unhandledRejection / Vue.errorHandler)一键挂载。\n *\n * 详见 design.md 5.5。完整实现(PV、点击、白屏耗时等)在「@gctrack/uni 完善」阶段补充。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { generateId, VISITOR_ID_KEY } from '@gctrack/core'\nimport { EventType, Platform } from '@gctrack/protocol'\nimport type { EventData, PersistenceAdapter } from '@gctrack/protocol'\n\n// 小程序运行时注入的全局(各端一致提供 uni / getCurrentPages)\ndeclare const uni: any\ndeclare function getCurrentPages(): any[]\n\n/** 平台适配器接口 —— core 通过它解耦浏览器 API,详见 design.md 5.5 */\nexport interface PlatformAdapter {\n getStorage(key: string): any\n setStorage(key: string, value: any): void\n removeStorage(key: string): void\n request(opts: {\n url: string\n method?: string\n data?: any\n header?: Record<string, string>\n }): Promise<{ statusCode: number; data: any }>\n getSystemInfo(): Record<string, any>\n getPageInfo(): { pathname: string; url: string; title: string }\n onUnload(cb: () => void): void\n}\n\n/** uni 适配实现 —— 全端用 uni.* 标准 API,不写 #ifdef */\nexport const uniAdapter: PlatformAdapter = {\n getStorage: (k) => {\n try {\n return uni.getStorageSync(k)\n } catch (e) {\n return null\n }\n },\n setStorage: (k, v) => {\n try {\n uni.setStorageSync(k, v)\n } catch (e) {\n /* ignore */\n }\n },\n removeStorage: (k) => {\n try {\n uni.removeStorageSync(k)\n } catch (e) {\n /* ignore */\n }\n },\n request: (opts) =>\n new Promise((resolve, reject) => {\n uni.request({\n url: opts.url,\n method: (opts.method || 'POST') as any,\n data: opts.data,\n header: opts.header || {},\n success: (res: any) => resolve({ statusCode: res.statusCode, data: res.data }),\n fail: (err: any) => reject(err),\n })\n }),\n getSystemInfo: () => {\n try {\n return uni.getSystemInfoSync()\n } catch (e) {\n return {}\n }\n },\n getPageInfo: () => {\n try {\n const pages = getCurrentPages()\n const top = pages[pages.length - 1]\n const route: string = (top && top.route) || ''\n const options = (top && top.options) || {}\n const query = Object.keys(options)\n .map((k) => `${k}=${options[k]}`)\n .join('&')\n return {\n pathname: '/' + route,\n url: '/' + route + (query ? '?' + query : ''),\n title: '',\n }\n } catch (e) {\n return { pathname: '', url: '', title: '' }\n }\n },\n onUnload: (cb) => {\n // 兜底:App.onHide / Page.onHide 由 installAppLifecycle 接管,这里注册 uni 级监听\n try {\n uni.onAppHide && uni.onAppHide(cb)\n } catch (e) {\n /* ignore */\n }\n },\n}\n\n/**\n * 构造基于 uni.request 的 sendFn,供 createTracker({ sendFn }) 使用。\n * 小程序无 sendBeacon/fetch,统一走 uni.request;header 值强制 String()(XHS 要求)。\n */\nexport function createUniSendFn(reportUrl: string, appKey?: string) {\n return (events: any[]): Promise<void> =>\n uniAdapter\n .request({\n url: reportUrl,\n method: 'POST',\n data: events,\n header: {\n 'content-type': 'application/json',\n 'X-App-Key': appKey ? String(appKey) : '',\n },\n })\n .then(() => undefined)\n}\n\n/** 根据 uni 运行环境推断 Platform 标识(写入 context.platform) */\nexport function detectPlatform(): string {\n try {\n const info = uni.getSystemInfoSync()\n // uni-app 注入 UNI_PLATFORM / uniPlatform\n const p = info.uniPlatform || info.platform\n if (typeof p === 'string') {\n if (p.includes('mp-weixin') || p.includes('weixin')) return Platform.WeixinMp\n if (p.includes('mp-alipay') || p.includes('alipay')) return Platform.AlipayMp\n if (p.includes('mp-jd') || p.includes('jd')) return Platform.JdMp\n if (p.includes('mp-xhs') || p.includes('xhs')) return Platform.XhsMp\n if (p.includes('mp-baidu') || p.includes('baidu')) return Platform.BaiduMp\n if (p.includes('h5')) return Platform.H5\n }\n } catch (e) {\n /* ignore */\n }\n return Platform.WeixinMp\n}\n\n/**\n * 兼容取组件名:Vue2 `vm.$options.name` / Vue3 `vm.type.name`。\n */\nfunction getComponentName(vm: any): string | undefined {\n if (!vm) return undefined\n const name =\n (vm.$options && (vm.$options.name || vm.$options._componentTag)) ||\n (vm.type && vm.type.name) ||\n (vm.$ && vm.$.type && vm.$.type.name)\n return name || undefined\n}\n\n/**\n * 错误捕获一键挂载(Vue2/Vue3 通用):\n * - appOrVue.config.errorHandler → vue_error\n * - uni.onUnhandledRejection → promise_error\n * App.onError 需在 App.vue 里手动调用 tracker.track(见 design.md 13.2)。\n */\nexport function installErrorCapture(appOrVue: any, tracker: Tracker): void {\n if (appOrVue && appOrVue.config) {\n appOrVue.config.errorHandler = (err: any, vm: any, info: string) => {\n tracker.track(EventType.VueError, {\n message: (err && err.message) || String(err),\n stack: err ? err.stack : undefined,\n info,\n componentName: getComponentName(vm),\n })\n }\n }\n try {\n uni.onUnhandledRejection &&\n uni.onUnhandledRejection((res: any) => {\n const reason = res ? res.reason : undefined\n tracker.track(EventType.PromiseError, {\n message: (reason && reason.message) || String(reason),\n stack: reason ? reason.stack : undefined,\n })\n })\n } catch (e) {\n /* ignore */\n }\n}\n\n/**\n * uni 端匿名访客 ID:走 uni storage(跨会话稳定),供 createTracker({ getVisitorId }) 注入。\n */\nexport function getUniVisitorId(): string {\n let id = uniAdapter.getStorage(VISITOR_ID_KEY)\n if (!id || typeof id !== 'string') {\n id = generateId()\n uniAdapter.setStorage(VISITOR_ID_KEY, id)\n }\n return id\n}\n\n/** 小程序持久化待发事件键(与 core Web 版同名) */\nconst MP_PENDING_KEY = '__gctrack_pending_events__'\n\n/**\n * 小程序离线持久化适配器:走 uniAdapter storage(uni.getStorageSync/setStorageSync),\n * 供 createTracker({ persistence: 'mp', persistenceAdapter: createMpPersistence() }) 注入。\n */\nexport function createMpPersistence(): PersistenceAdapter {\n return {\n load(): Promise<EventData[]> {\n let events: EventData[] = []\n try {\n const raw = uniAdapter.getStorage(MP_PENDING_KEY)\n if (raw) {\n events = (typeof raw === 'string' ? JSON.parse(raw) : raw) as EventData[]\n uniAdapter.removeStorage(MP_PENDING_KEY)\n }\n } catch (e) {\n events = []\n }\n return Promise.resolve(events)\n },\n save(events: EventData[]): Promise<void> {\n try {\n uniAdapter.setStorage(MP_PENDING_KEY, JSON.stringify(events))\n } catch (e) {\n /* ignore */\n }\n return Promise.resolve()\n },\n clear(): Promise<void> {\n try {\n uniAdapter.removeStorage(MP_PENDING_KEY)\n } catch (e) {\n /* ignore */\n }\n return Promise.resolve()\n },\n }\n}\n\n/**\n * 小程序自动 PV:全局 mixin onShow,取 getCurrentPages() 栈顶 route+options 拼 pathname\n * 上报 page_view,并显式写 event.pathname(小程序无 window.location,core autoCollect 取不到)。\n */\nexport function installPageView(appOrVue: any, tracker: Tracker): void {\n appOrVue.mixin({\n onShow(this: any) {\n const info = uniAdapter.getPageInfo()\n tracker.track(\n EventType.PageView,\n { route: info.url },\n { pathname: info.pathname, url: info.url, title: info.title },\n )\n },\n })\n}\n\n/**\n * uni 插件选项\n */\nexport interface UniPluginOptions {\n tracker: Tracker\n /** 是否自动采集 PV(默认 true,挂全局 onShow mixin) */\n trackPageView?: boolean\n}\n\n/**\n * GCTrack uni 插件对象(Vue2/Vue3 通用)。\n * - 全局属性:V2 prototype / V3 globalProperties\n * - 错误捕获:errorHandler(委托 installErrorCapture)\n * - mixin:暴露 $track / $trackPageView\n * - PV 采集:默认挂 installPageView(onShow)\n */\nexport const uniPlugin = {\n install(appOrVue: any, options: UniPluginOptions): void {\n const { tracker, trackPageView = true } = options\n const v2 = typeof appOrVue === 'function'\n\n if (v2) {\n appOrVue.prototype.$tracker = tracker\n } else {\n appOrVue.config.globalProperties.$tracker = tracker\n }\n\n installErrorCapture(appOrVue, tracker)\n\n // Vue2/3 都有 .mixin\n appOrVue.mixin({\n methods: {\n $track(this: any, eventType: string, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(eventType, data)\n }\n },\n $trackPageView(this: any, data?: Record<string, any>): void {\n if (this.$tracker) {\n this.$tracker.track(EventType.PageView, data)\n }\n },\n },\n })\n\n if (trackPageView) {\n installPageView(appOrVue, tracker)\n }\n },\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gctrack/uni",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "GCTrack 小程序多端适配 —— uni-app 微信/支付宝/京东/小红书/H5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -32,13 +32,18 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@gctrack/protocol": "0.
|
|
35
|
+
"@gctrack/protocol": "0.2.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@gctrack/core": "0.
|
|
38
|
+
"@gctrack/core": "0.2.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"happy-dom": "^15.0.0",
|
|
42
|
+
"vitest": "^2.0.0"
|
|
39
43
|
},
|
|
40
44
|
"scripts": {
|
|
41
45
|
"build": "tsdown",
|
|
42
|
-
"dev": "tsdown --watch"
|
|
46
|
+
"dev": "tsdown --watch",
|
|
47
|
+
"test": "vitest run"
|
|
43
48
|
}
|
|
44
49
|
}
|