monitor-track 1.10.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/CHANGELOG.md +31 -0
- package/README.md +101 -0
- package/dist/CHANGELOG.md +21 -0
- package/dist/README.md +101 -0
- package/dist/cjs/config/global.d.ts +17 -0
- package/dist/cjs/config/index.d.ts +33 -0
- package/dist/cjs/constant.d.ts +2 -0
- package/dist/cjs/handlers/error.d.ts +23 -0
- package/dist/cjs/handlers/index.d.ts +3 -0
- package/dist/cjs/handlers/pv.d.ts +24 -0
- package/dist/cjs/handlers/user-activity.d.ts +9 -0
- package/dist/cjs/index.d.ts +30 -0
- package/dist/cjs/index.js +1485 -0
- package/dist/cjs/main.d.ts +1 -0
- package/dist/cjs/reporter.d.ts +198 -0
- package/dist/cjs/types/config.d.ts +59 -0
- package/dist/cjs/types/global.d.ts +70 -0
- package/dist/cjs/types/index.d.ts +189 -0
- package/dist/cjs/utils/index.d.ts +45 -0
- package/dist/esm/_virtual/_tslib.js +26 -0
- package/dist/esm/config/global.d.ts +17 -0
- package/dist/esm/config/global.js +271 -0
- package/dist/esm/config/index.d.ts +33 -0
- package/dist/esm/config/index.js +32 -0
- package/dist/esm/constant.d.ts +2 -0
- package/dist/esm/constant.js +4 -0
- package/dist/esm/handlers/error.d.ts +23 -0
- package/dist/esm/handlers/error.js +181 -0
- package/dist/esm/handlers/index.d.ts +3 -0
- package/dist/esm/handlers/pv.d.ts +24 -0
- package/dist/esm/handlers/pv.js +99 -0
- package/dist/esm/handlers/user-activity.d.ts +9 -0
- package/dist/esm/handlers/user-activity.js +66 -0
- package/dist/esm/index.d.ts +30 -0
- package/dist/esm/index.js +115 -0
- package/dist/esm/main.d.ts +1 -0
- package/dist/esm/package.json.js +3 -0
- package/dist/esm/reporter.d.ts +198 -0
- package/dist/esm/reporter.js +359 -0
- package/dist/esm/types/config.d.ts +59 -0
- package/dist/esm/types/global.d.ts +70 -0
- package/dist/esm/types/index.d.ts +189 -0
- package/dist/esm/utils/index.d.ts +45 -0
- package/dist/esm/utils/index.js +354 -0
- package/dist/index.js +1534 -0
- package/dist/package.json +41 -0
- package/package.json +42 -0
- package/rollup.config.js +66 -0
- package/scripts/cp.js +11 -0
- package/src/config/global.ts +309 -0
- package/src/config/index.ts +53 -0
- package/src/constant.ts +2 -0
- package/src/handlers/error.ts +187 -0
- package/src/handlers/index.ts +3 -0
- package/src/handlers/pv.ts +124 -0
- package/src/handlers/user-activity.ts +69 -0
- package/src/index.ts +127 -0
- package/src/main.ts +8 -0
- package/src/reporter.ts +372 -0
- package/src/types/config.ts +58 -0
- package/src/types/global.ts +73 -0
- package/src/types/index.ts +227 -0
- package/src/typing.d.ts +15 -0
- package/src/utils/index.ts +371 -0
- package/tsconfig.esm.json +14 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { INavigator } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* @description 获取uuid
|
|
4
|
+
*/
|
|
5
|
+
export declare function getUid(): string;
|
|
6
|
+
/**
|
|
7
|
+
* @description 获取session id
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSessionId(): string;
|
|
10
|
+
/**
|
|
11
|
+
* @description 获取浏览器信息
|
|
12
|
+
*/
|
|
13
|
+
export declare function getNavigator(): INavigator;
|
|
14
|
+
/**
|
|
15
|
+
* @description 获取viewport的宽高
|
|
16
|
+
*/
|
|
17
|
+
export declare function getViewport(): string;
|
|
18
|
+
/**
|
|
19
|
+
* @description 获取元素路径,最多保留5层
|
|
20
|
+
* @param e
|
|
21
|
+
*/
|
|
22
|
+
export declare const getElmPath: (target: any) => string;
|
|
23
|
+
/**
|
|
24
|
+
* @description 序列化对象
|
|
25
|
+
* @param obj
|
|
26
|
+
*/
|
|
27
|
+
export declare function serialize(obj: {
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
}): string;
|
|
30
|
+
/**
|
|
31
|
+
* @description 注册事件监听
|
|
32
|
+
* @param event 事件
|
|
33
|
+
* @param fn 回调方法
|
|
34
|
+
*/
|
|
35
|
+
export declare const on: (event: string, fn: (e: Event) => void) => void;
|
|
36
|
+
/**
|
|
37
|
+
* @description 移除事件监听
|
|
38
|
+
* @param event 事件
|
|
39
|
+
* @param fn 回调方法
|
|
40
|
+
*/
|
|
41
|
+
export declare const off: (event: any, fn: (e: Event) => void) => any;
|
|
42
|
+
export declare const visualTrackFunc: () => void;
|
|
43
|
+
export declare const initWindowObjectFunction: () => void;
|
|
44
|
+
export declare const handleLocationChange: (e: Event) => void;
|
|
45
|
+
export declare function debounce(fn: Function): (...arg: unknown[]) => void;
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { v4 } from 'uuid';
|
|
4
|
+
import { UAParser } from 'ua-parser-js';
|
|
5
|
+
import { shuyunTrackSessionId, shuyunTrackId } from '../constant.js';
|
|
6
|
+
import { setReportValue, getReport } from '../config/global.js';
|
|
7
|
+
import { report } from '../reporter.js';
|
|
8
|
+
import { Config } from '../config/index.js';
|
|
9
|
+
import { version } from '../package.json.js';
|
|
10
|
+
import { getUserEvents, getFullScreenShoot } from '../handlers/error.js';
|
|
11
|
+
import { handleHistoryChange } from '../handlers/pv.js';
|
|
12
|
+
|
|
13
|
+
const parser = new UAParser();
|
|
14
|
+
/**
|
|
15
|
+
* @description 获取uuid
|
|
16
|
+
*/
|
|
17
|
+
function getUid() {
|
|
18
|
+
let uid = localStorage.getItem(shuyunTrackId) || '';
|
|
19
|
+
if (!uid) {
|
|
20
|
+
uid = v4();
|
|
21
|
+
localStorage.setItem(shuyunTrackId, uid);
|
|
22
|
+
}
|
|
23
|
+
return uid;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* @description 获取session id
|
|
27
|
+
*/
|
|
28
|
+
function getSessionId() {
|
|
29
|
+
const sessionId = sessionStorage.getItem(shuyunTrackSessionId);
|
|
30
|
+
if (sessionId) {
|
|
31
|
+
return sessionId;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const id = v4();
|
|
35
|
+
sessionStorage.setItem(shuyunTrackSessionId, id);
|
|
36
|
+
return id;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @description 获取浏览器信息
|
|
41
|
+
*/
|
|
42
|
+
function getNavigator() {
|
|
43
|
+
var _a;
|
|
44
|
+
const uaResult = parser.getResult();
|
|
45
|
+
return {
|
|
46
|
+
language: navigator.language,
|
|
47
|
+
navigatorVendor: navigator.vendor,
|
|
48
|
+
connectionType: ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.connection) === null || _a === void 0 ? void 0 : _a.effectiveType) || '2g',
|
|
49
|
+
browserName: uaResult.browser.name || '',
|
|
50
|
+
browserVersion: uaResult.browser.version || '',
|
|
51
|
+
engineName: uaResult.engine.name || '',
|
|
52
|
+
engineVersion: uaResult.engine.version || '',
|
|
53
|
+
osName: uaResult.os.name || '',
|
|
54
|
+
osVersion: uaResult.os.version || '',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @description 获取viewport的宽高
|
|
59
|
+
*/
|
|
60
|
+
function getViewport() {
|
|
61
|
+
const w = document.documentElement.clientWidth || document.body.clientWidth;
|
|
62
|
+
const h = document.documentElement.clientHeight || document.body.clientHeight;
|
|
63
|
+
return `${w} x ${h}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* @description 获取元素路径,最多保留5层
|
|
67
|
+
* @param e
|
|
68
|
+
*/
|
|
69
|
+
const getElmPath = function (target) {
|
|
70
|
+
if (!target || target.nodeType !== 1) {
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
const ret = [];
|
|
74
|
+
// 层数,最多5层
|
|
75
|
+
let deepLength = 0;
|
|
76
|
+
// 元素
|
|
77
|
+
let elm = '';
|
|
78
|
+
if (typeof target.innerText === 'string') {
|
|
79
|
+
ret.push(`(${target.innerText.substr(0, 50)})`);
|
|
80
|
+
}
|
|
81
|
+
for (let t = target || null; t && deepLength++ < 5 && !((elm = normalTarget(t)) === 'html');) {
|
|
82
|
+
// eslint-disable-next-line no-sequences
|
|
83
|
+
ret.push(elm), (t = t.parentNode);
|
|
84
|
+
}
|
|
85
|
+
return ret.reverse().join(' > ');
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* @description 处理html node
|
|
89
|
+
* @param e
|
|
90
|
+
*/
|
|
91
|
+
const normalTarget = function (target) {
|
|
92
|
+
let t, n, r, a, i;
|
|
93
|
+
const o = [];
|
|
94
|
+
if (!target || !target.tagName) {
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
o.push(target.tagName.toLowerCase());
|
|
98
|
+
if (target.id) {
|
|
99
|
+
o.push('#'.concat(target.id));
|
|
100
|
+
}
|
|
101
|
+
if ((t = target.className) && Object.prototype.toString.call(t) === '[object String]') {
|
|
102
|
+
for (n = t.split(/\s+/), i = 0; i < n.length; i++) {
|
|
103
|
+
// className包含active的不加入路径
|
|
104
|
+
if (n[i].indexOf('active') < 0)
|
|
105
|
+
o.push('.'.concat(n[i]));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const s = ['type', 'name', 'title', 'alt'];
|
|
109
|
+
for (i = 0; i < s.length; i++) {
|
|
110
|
+
r = s[i];
|
|
111
|
+
if ((a = target.getAttribute(r))) {
|
|
112
|
+
o.push('['.concat(r, '="').concat(a, '"]'));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return o.join('');
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* @description 序列化对象
|
|
119
|
+
* @param obj
|
|
120
|
+
*/
|
|
121
|
+
function serialize(obj) {
|
|
122
|
+
const str = [];
|
|
123
|
+
for (const p in obj) {
|
|
124
|
+
if (Object.prototype.hasOwnProperty.call(obj, p) && typeof obj[p] !== 'undefined') {
|
|
125
|
+
const value = typeof obj[p] === 'object' ? JSON.stringify(obj[p]) : obj[p];
|
|
126
|
+
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(value));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return str.join('&');
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* @description 注册事件监听
|
|
133
|
+
* @param event 事件
|
|
134
|
+
* @param fn 回调方法
|
|
135
|
+
*/
|
|
136
|
+
const on = function (event, fn) {
|
|
137
|
+
if (window.addEventListener) {
|
|
138
|
+
window.addEventListener(event, fn, true);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
window.attachEvent(`on${event}`, fn);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* @description 移除事件监听
|
|
146
|
+
* @param event 事件
|
|
147
|
+
* @param fn 回调方法
|
|
148
|
+
*/
|
|
149
|
+
const off = function (event, fn) {
|
|
150
|
+
if (window.removeEventListener) {
|
|
151
|
+
return window.removeEventListener(event, fn);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
return window.detachEvent(`on${event}`, fn);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const formatTrackElementXPath = (xPath) => {
|
|
158
|
+
const result = [];
|
|
159
|
+
const array = xPath.split('/');
|
|
160
|
+
array.forEach((item) => {
|
|
161
|
+
if (!['svg', 'path', 'g', 'image', 'text', 'line', 'rect', 'polygon', 'circle', 'ellipse'].some((child) => {
|
|
162
|
+
if (item.toLowerCase().split('[')[0] === child) {
|
|
163
|
+
result.push(`/*[name()="${child}"]`);
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
})) {
|
|
170
|
+
result.push(item);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
return result.join('/');
|
|
174
|
+
};
|
|
175
|
+
const formatElementXPath = (info) => {
|
|
176
|
+
var _a;
|
|
177
|
+
let elementXPathValue = '';
|
|
178
|
+
const elementXPath = info.elementXPath;
|
|
179
|
+
if (elementXPath) {
|
|
180
|
+
const xpathElement = document.evaluate(formatTrackElementXPath(elementXPath), document).iterateNext();
|
|
181
|
+
elementXPathValue = xpathElement ? (_a = (xpathElement.textContent || xpathElement.value)) === null || _a === void 0 ? void 0 : _a.trim() : '';
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
elementXPath,
|
|
185
|
+
elementXPathValue,
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
let existTrackListenEvent = {};
|
|
189
|
+
const elements = [];
|
|
190
|
+
let timeout;
|
|
191
|
+
const visualTrackFunc = () => {
|
|
192
|
+
if (Config.enableVisualTrack) {
|
|
193
|
+
if (timeout)
|
|
194
|
+
clearTimeout(timeout);
|
|
195
|
+
timeout = setTimeout(() => {
|
|
196
|
+
timeout = null;
|
|
197
|
+
const url = location.href.split('?')[0];
|
|
198
|
+
axios
|
|
199
|
+
.get(`${Config.reportUrl.replace('/s/r', '')}/visual/get_data_list?url=${encodeURIComponent(url)}`)
|
|
200
|
+
.then((res) => {
|
|
201
|
+
var _a, _b;
|
|
202
|
+
const listData = (_b = (_a = res.data.result) === null || _a === void 0 ? void 0 : _a.result) === null || _b === void 0 ? void 0 : _b.dataList;
|
|
203
|
+
if (Array.isArray(listData)) {
|
|
204
|
+
try {
|
|
205
|
+
listData.forEach((item) => {
|
|
206
|
+
if (item.trackType === 'mount') {
|
|
207
|
+
visualReportEvent(item);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const element = document
|
|
211
|
+
.evaluate(formatTrackElementXPath(item.trackElementXPath), document)
|
|
212
|
+
.iterateNext();
|
|
213
|
+
const key = url + item.trackElementXPath;
|
|
214
|
+
if (element) {
|
|
215
|
+
if (!existTrackListenEvent[key]) {
|
|
216
|
+
existTrackListenEvent[key] = true;
|
|
217
|
+
elements.push(element);
|
|
218
|
+
//@ts-ignore
|
|
219
|
+
element.setAttribute('visual-track-data-attr', JSON.stringify(item));
|
|
220
|
+
element.addEventListener('click', clickEventFunc);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
const func = () => {
|
|
225
|
+
var _a;
|
|
226
|
+
const { browserName, browserVersion } = getNavigator();
|
|
227
|
+
const payload = {
|
|
228
|
+
projectID: Config.projectID,
|
|
229
|
+
version,
|
|
230
|
+
url,
|
|
231
|
+
trackElementXPath: item.trackElementXPath,
|
|
232
|
+
trackNameInfo: item.trackNameInfo,
|
|
233
|
+
params: item.params,
|
|
234
|
+
customPayload: Config.customPayload,
|
|
235
|
+
type: 'visual_track_xpath_not_found',
|
|
236
|
+
browser: `${browserName} - ${browserVersion}`,
|
|
237
|
+
};
|
|
238
|
+
if (typeof ((_a = window.navigator) === null || _a === void 0 ? void 0 : _a.sendBeacon) === 'function') {
|
|
239
|
+
const formData = new FormData();
|
|
240
|
+
for (const i in payload) {
|
|
241
|
+
if (Object.prototype.hasOwnProperty.call(payload, i)) {
|
|
242
|
+
const value = payload[i];
|
|
243
|
+
formData.append(i, value && typeof value === 'object' ? JSON.stringify(value) : value);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
window.navigator.sendBeacon(Config.reportUrl, formData);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
new Image().src = `${Config.reportUrl}?${serialize(payload)}`;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
if (typeof window.requestIdleCallback === 'function') {
|
|
253
|
+
window.requestIdleCallback(() => func(), { timeout: 2000 });
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
setTimeout(() => func(), 0);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
// eslint-disable-next-line no-console
|
|
264
|
+
console.log('visual track evaluate err', err);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}, 1000);
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const visualReportEvent = (item) => {
|
|
272
|
+
var _a;
|
|
273
|
+
const { elementXPath, elementXPathValue } = formatElementXPath(item.trackNameInfo);
|
|
274
|
+
const visualTrackData = {
|
|
275
|
+
trackType: item.trackType,
|
|
276
|
+
trackName: elementXPath ? elementXPathValue : item.trackNameInfo.name,
|
|
277
|
+
params: (_a = item.params) === null || _a === void 0 ? void 0 : _a.map((child) => {
|
|
278
|
+
const { elementXPath, elementXPathValue } = formatElementXPath(child);
|
|
279
|
+
return {
|
|
280
|
+
name: child.name,
|
|
281
|
+
value: elementXPath ? elementXPathValue : child.value,
|
|
282
|
+
};
|
|
283
|
+
}),
|
|
284
|
+
};
|
|
285
|
+
setReportValue('type', 'visual');
|
|
286
|
+
setReportValue('vD', visualTrackData);
|
|
287
|
+
report(getReport());
|
|
288
|
+
setReportValue('vD', undefined);
|
|
289
|
+
};
|
|
290
|
+
const clickEventFunc = (e) => {
|
|
291
|
+
//@ts-ignore
|
|
292
|
+
const item = JSON.parse(e.target.getAttribute('visual-track-data-attr'));
|
|
293
|
+
visualReportEvent(item);
|
|
294
|
+
};
|
|
295
|
+
const initWindowObjectFunction = () => {
|
|
296
|
+
if (typeof window.manualReportTrackFunc === 'undefined') {
|
|
297
|
+
window.manualReportTrackFunc = (data) => {
|
|
298
|
+
if (Object.prototype.toString.call(data) !== '[object Object]') {
|
|
299
|
+
// eslint-disable-next-line no-console
|
|
300
|
+
console.warn('manualReportTrackFunc参数必须是一个对象!');
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
setReportValue('type', 'manual');
|
|
304
|
+
setReportValue('manualReport', data);
|
|
305
|
+
report(getReport());
|
|
306
|
+
setReportValue('manualReport', undefined);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (typeof window.getFullScreenShootFunc === 'undefined') {
|
|
311
|
+
//下载页面截图
|
|
312
|
+
window.getFullScreenShootFunc = (filename) => __awaiter(void 0, void 0, void 0, function* () {
|
|
313
|
+
const file = yield getFullScreenShoot(filename);
|
|
314
|
+
const url = window.URL.createObjectURL(file);
|
|
315
|
+
const tagA = document.createElement('a');
|
|
316
|
+
tagA.setAttribute('href', url);
|
|
317
|
+
tagA.setAttribute('download', file.name);
|
|
318
|
+
tagA.setAttribute('target', '_blank');
|
|
319
|
+
document.body.appendChild(tagA);
|
|
320
|
+
tagA.click();
|
|
321
|
+
document.body.removeChild(tagA);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
if (typeof window.getRRWebUserEventsCaptureFunc === 'undefined') {
|
|
325
|
+
window.getRRWebUserEventsCaptureFunc = () => {
|
|
326
|
+
setReportValue('type', 'error');
|
|
327
|
+
setReportValue('error', {
|
|
328
|
+
subType: 'manual',
|
|
329
|
+
message: 'manual trigger',
|
|
330
|
+
events: getUserEvents(true),
|
|
331
|
+
});
|
|
332
|
+
report(getReport());
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
let prewHref = '';
|
|
337
|
+
const handleLocationChange = (e) => {
|
|
338
|
+
const curHref = location.href;
|
|
339
|
+
// href中`?`后面的值改变,不触发后续动作
|
|
340
|
+
if (prewHref.split('?')[0] === curHref.split('?')[0]) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
prewHref = curHref;
|
|
344
|
+
handleHistoryChange();
|
|
345
|
+
elements.forEach((element) => {
|
|
346
|
+
element === null || element === void 0 ? void 0 : element.removeEventListener('click', clickEventFunc);
|
|
347
|
+
});
|
|
348
|
+
//清空可视化埋点之前的数据
|
|
349
|
+
existTrackListenEvent = {};
|
|
350
|
+
elements.length = 0;
|
|
351
|
+
visualTrackFunc();
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
export { getElmPath, getNavigator, getSessionId, getUid, getViewport, handleLocationChange, initWindowObjectFunction, off, on, serialize, visualTrackFunc };
|