monitor-track 1.10.0 → 1.10.2
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 +9 -0
- package/{dist/cjs → cjs}/index.js +1 -1
- package/esm/package.json.js +3 -0
- package/{dist/index.js → index.js} +1 -1
- package/package.json +2 -2
- package/dist/CHANGELOG.md +0 -21
- package/dist/README.md +0 -101
- package/dist/esm/package.json.js +0 -3
- package/dist/package.json +0 -41
- package/rollup.config.js +0 -66
- package/scripts/cp.js +0 -11
- package/src/config/global.ts +0 -309
- package/src/config/index.ts +0 -53
- package/src/constant.ts +0 -2
- package/src/handlers/error.ts +0 -187
- package/src/handlers/index.ts +0 -3
- package/src/handlers/pv.ts +0 -124
- package/src/handlers/user-activity.ts +0 -69
- package/src/index.ts +0 -127
- package/src/main.ts +0 -8
- package/src/reporter.ts +0 -372
- package/src/types/config.ts +0 -58
- package/src/types/global.ts +0 -73
- package/src/types/index.ts +0 -227
- package/src/typing.d.ts +0 -15
- package/src/utils/index.ts +0 -371
- package/tsconfig.esm.json +0 -14
- /package/{dist/cjs → cjs}/config/global.d.ts +0 -0
- /package/{dist/cjs → cjs}/config/index.d.ts +0 -0
- /package/{dist/cjs → cjs}/constant.d.ts +0 -0
- /package/{dist/cjs → cjs}/handlers/error.d.ts +0 -0
- /package/{dist/cjs → cjs}/handlers/index.d.ts +0 -0
- /package/{dist/cjs → cjs}/handlers/pv.d.ts +0 -0
- /package/{dist/cjs → cjs}/handlers/user-activity.d.ts +0 -0
- /package/{dist/cjs → cjs}/index.d.ts +0 -0
- /package/{dist/cjs → cjs}/main.d.ts +0 -0
- /package/{dist/cjs → cjs}/reporter.d.ts +0 -0
- /package/{dist/cjs → cjs}/types/config.d.ts +0 -0
- /package/{dist/cjs → cjs}/types/global.d.ts +0 -0
- /package/{dist/cjs → cjs}/types/index.d.ts +0 -0
- /package/{dist/cjs → cjs}/utils/index.d.ts +0 -0
- /package/{dist/esm → esm}/_virtual/_tslib.js +0 -0
- /package/{dist/esm → esm}/config/global.d.ts +0 -0
- /package/{dist/esm → esm}/config/global.js +0 -0
- /package/{dist/esm → esm}/config/index.d.ts +0 -0
- /package/{dist/esm → esm}/config/index.js +0 -0
- /package/{dist/esm → esm}/constant.d.ts +0 -0
- /package/{dist/esm → esm}/constant.js +0 -0
- /package/{dist/esm → esm}/handlers/error.d.ts +0 -0
- /package/{dist/esm → esm}/handlers/error.js +0 -0
- /package/{dist/esm → esm}/handlers/index.d.ts +0 -0
- /package/{dist/esm → esm}/handlers/pv.d.ts +0 -0
- /package/{dist/esm → esm}/handlers/pv.js +0 -0
- /package/{dist/esm → esm}/handlers/user-activity.d.ts +0 -0
- /package/{dist/esm → esm}/handlers/user-activity.js +0 -0
- /package/{dist/esm → esm}/index.d.ts +0 -0
- /package/{dist/esm → esm}/index.js +0 -0
- /package/{dist/esm → esm}/main.d.ts +0 -0
- /package/{dist/esm → esm}/reporter.d.ts +0 -0
- /package/{dist/esm → esm}/reporter.js +0 -0
- /package/{dist/esm → esm}/types/config.d.ts +0 -0
- /package/{dist/esm → esm}/types/global.d.ts +0 -0
- /package/{dist/esm → esm}/types/index.d.ts +0 -0
- /package/{dist/esm → esm}/utils/index.d.ts +0 -0
- /package/{dist/esm → esm}/utils/index.js +0 -0
package/src/handlers/error.ts
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: Mark.Zhang
|
|
3
|
-
* @Date: 2020-10-26 11:10:04
|
|
4
|
-
* @Description 资源加载错误及js错误相关的处理方法
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import * as rrweb from 'rrweb';
|
|
8
|
-
import ErrorStackParser from 'error-stack-parser';
|
|
9
|
-
import html2canvas from 'html2canvas';
|
|
10
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
11
|
-
import { report } from '../reporter';
|
|
12
|
-
import { getReport, setReportValue } from '../config/global';
|
|
13
|
-
import { IReport } from '../types/global';
|
|
14
|
-
import { Config } from '../config';
|
|
15
|
-
|
|
16
|
-
const eventsMatrix: any[][] = [[]];
|
|
17
|
-
|
|
18
|
-
rrweb.record({
|
|
19
|
-
emit(event, isCheckout) {
|
|
20
|
-
// isCheckout 是一个标识,告诉你重新制作了快照
|
|
21
|
-
if (isCheckout) {
|
|
22
|
-
eventsMatrix.push([]);
|
|
23
|
-
}
|
|
24
|
-
if (eventsMatrix.length > 2) {
|
|
25
|
-
eventsMatrix.shift();
|
|
26
|
-
}
|
|
27
|
-
const lastEvents = eventsMatrix[eventsMatrix.length - 1];
|
|
28
|
-
lastEvents.push(event);
|
|
29
|
-
},
|
|
30
|
-
// 每30秒重新制作快照
|
|
31
|
-
checkoutEveryNms: 30 * 1000,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @description 错误事件触发后的操作
|
|
36
|
-
*/
|
|
37
|
-
export function handleError(event: ErrorEvent | Event | PromiseRejectionEvent): void {
|
|
38
|
-
setReportValue<IReport, 'type'>('type', 'error');
|
|
39
|
-
if (event.type === 'error') {
|
|
40
|
-
if (event instanceof ErrorEvent) {
|
|
41
|
-
setCaughtError(event);
|
|
42
|
-
} else {
|
|
43
|
-
setResourceError(event);
|
|
44
|
-
}
|
|
45
|
-
} else if (event.type === 'unhandledrejection') {
|
|
46
|
-
setPromiseError(event as PromiseRejectionEvent);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* @description 设置错误信息
|
|
52
|
-
*/
|
|
53
|
-
export function setCaughtError(event: ErrorEvent) {
|
|
54
|
-
if (ignoreError(event.message)) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
let filename = event.filename,
|
|
58
|
-
line = event.lineno,
|
|
59
|
-
column = event.colno,
|
|
60
|
-
functionName = '',
|
|
61
|
-
stackFrame = JSON.stringify([]);
|
|
62
|
-
if (event.error && event.error.stack) {
|
|
63
|
-
const error = ErrorStackParser.parse(event.error);
|
|
64
|
-
stackFrame = JSON.stringify(error);
|
|
65
|
-
const info = error.find((item) => item.fileName && !/node_modules|vendor|bundle/.test(item.fileName));
|
|
66
|
-
if (info) {
|
|
67
|
-
filename = info.fileName!;
|
|
68
|
-
line = Number(info.lineNumber);
|
|
69
|
-
column = Number(info.columnNumber);
|
|
70
|
-
functionName = info.functionName || '';
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
setReportValue<IReport, 'error'>('error', {
|
|
74
|
-
subType: 'js',
|
|
75
|
-
line,
|
|
76
|
-
column,
|
|
77
|
-
message: event.message,
|
|
78
|
-
filename,
|
|
79
|
-
functionName,
|
|
80
|
-
stack: event?.error?.stack?.substring(0, Config.maxLength) || '',
|
|
81
|
-
stackFrame,
|
|
82
|
-
events: getUserEvents(false),
|
|
83
|
-
});
|
|
84
|
-
report(getReport());
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @description 设置异步错误信息
|
|
89
|
-
*/
|
|
90
|
-
export function setPromiseError(event: PromiseRejectionEvent) {
|
|
91
|
-
let message = event.reason;
|
|
92
|
-
if (event.reason && typeof event.reason === 'object') {
|
|
93
|
-
message = JSON.stringify(event.reason);
|
|
94
|
-
if (message === '{}') {
|
|
95
|
-
message = event.reason.stack;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (ignoreError(message)) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
setReportValue<IReport, 'error'>('error', {
|
|
102
|
-
subType: 'async',
|
|
103
|
-
message,
|
|
104
|
-
events: getUserEvents(false),
|
|
105
|
-
});
|
|
106
|
-
report(getReport());
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* @description 设置资源错误信息
|
|
111
|
-
*/
|
|
112
|
-
export function setResourceError(event: Event) {
|
|
113
|
-
const target = event.target as any;
|
|
114
|
-
if (ignoreError(target.outerHTML)) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
setReportValue<IReport, 'error'>('error', {
|
|
118
|
-
subType: 'resource',
|
|
119
|
-
message: target.outerHTML,
|
|
120
|
-
filename: target.src || target.currentSrc,
|
|
121
|
-
stack: target.localName.toUpperCase().substring(0, Config.maxLength),
|
|
122
|
-
events: getUserEvents(false),
|
|
123
|
-
});
|
|
124
|
-
report(getReport());
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* 忽略的error
|
|
129
|
-
* @param errorMsg 错误信息
|
|
130
|
-
*/
|
|
131
|
-
export function ignoreError(errorMsg: string) {
|
|
132
|
-
const errors = Config?.ignore?.errors || [];
|
|
133
|
-
|
|
134
|
-
const existIgnoreError = errors.findIndex((item) => {
|
|
135
|
-
if (typeof item === 'string') {
|
|
136
|
-
return item === errorMsg;
|
|
137
|
-
} else if (Object.prototype.toString.call(item) === '[object Object]') {
|
|
138
|
-
if (item.regExp && typeof item.input === 'string') {
|
|
139
|
-
const regex = new RegExp(item.input, 'g');
|
|
140
|
-
return regex.test(errorMsg);
|
|
141
|
-
}
|
|
142
|
-
return false;
|
|
143
|
-
} else {
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return existIgnoreError > -1;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* 获取用户最近得操作,视频录像时间应当在30秒到60秒之间
|
|
153
|
-
*/
|
|
154
|
-
let lastGetTime = Date.now(); //缓存操作录像,防止段时间内大量获取录像数据导滞内存溢出
|
|
155
|
-
export function getUserEvents(notUseCache: boolean) {
|
|
156
|
-
let events;
|
|
157
|
-
if (Date.now() - lastGetTime > 2000 || notUseCache) {
|
|
158
|
-
lastGetTime = Date.now();
|
|
159
|
-
if (eventsMatrix.length >= 2) {
|
|
160
|
-
const finalVideoData = eventsMatrix[eventsMatrix.length - 1];
|
|
161
|
-
events = JSON.stringify(eventsMatrix[eventsMatrix.length - 2].concat(finalVideoData));
|
|
162
|
-
if (events.length > 1024 * 1024 * 15 && JSON.stringify(finalVideoData).length > 1024 * 1024) {
|
|
163
|
-
//如果录像数据量太大且最后那个分片的数据量不算小,那么缩短上报的录像时长
|
|
164
|
-
events = JSON.stringify(eventsMatrix[eventsMatrix.length - 1]);
|
|
165
|
-
}
|
|
166
|
-
} else {
|
|
167
|
-
events = JSON.stringify(eventsMatrix);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return events;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export function getFullScreenShoot(filename: string | undefined): Promise<File> {
|
|
174
|
-
const name = filename || uuidv4();
|
|
175
|
-
return html2canvas(document.body).then(function (canvas) {
|
|
176
|
-
const urlData = canvas.toDataURL('image/png', 1);
|
|
177
|
-
const bytes = window.atob(urlData.split(',')[1]);
|
|
178
|
-
const mime = urlData!.split(',')[0]!.match(/:(.*?);/)?.[1];
|
|
179
|
-
const ab = new ArrayBuffer(bytes.length);
|
|
180
|
-
const ia = new Uint8Array(ab);
|
|
181
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
182
|
-
ia[i] = bytes.charCodeAt(i);
|
|
183
|
-
}
|
|
184
|
-
const file = new File([ab], `${name}.png`, { type: mime });
|
|
185
|
-
return file;
|
|
186
|
-
});
|
|
187
|
-
}
|
package/src/handlers/index.ts
DELETED
package/src/handlers/pv.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/* eslint-disable prefer-rest-params */
|
|
2
|
-
/*
|
|
3
|
-
* @Author: Mark.Zhang
|
|
4
|
-
* @Date: 2020-10-26 11:10:04
|
|
5
|
-
* @Description 路由相关的处理方法
|
|
6
|
-
*/
|
|
7
|
-
import { getReport, setReportValue } from '../config/global';
|
|
8
|
-
import { report } from '../reporter';
|
|
9
|
-
import { Config } from '../config';
|
|
10
|
-
import { IReport } from '../types/global';
|
|
11
|
-
import { visualTrackFunc } from '../utils';
|
|
12
|
-
|
|
13
|
-
/** 路由栈数组,存储路由变化信息 */
|
|
14
|
-
let routerStack: string[] = [];
|
|
15
|
-
|
|
16
|
-
/** 路由触发的时间 */
|
|
17
|
-
let time = 0;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @description 派发pushState, replaceState 的监听
|
|
21
|
-
* @param type
|
|
22
|
-
*/
|
|
23
|
-
export function _history(type: 'pushState' | 'replaceState') {
|
|
24
|
-
const origin = history[type];
|
|
25
|
-
return function () {
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
const r = origin.apply(this, arguments);
|
|
28
|
-
const e = new Event(type);
|
|
29
|
-
// @ts-ignore
|
|
30
|
-
(e as any).arguments = arguments;
|
|
31
|
-
window.dispatchEvent(e);
|
|
32
|
-
return r;
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @description 处理hash变化
|
|
38
|
-
* @param e hash事件
|
|
39
|
-
*/
|
|
40
|
-
export function handleHashChange(__e: Event) {
|
|
41
|
-
if (Config.spa && Config.hash) {
|
|
42
|
-
setReport();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @description 处理history变化
|
|
48
|
-
* @param e history事件
|
|
49
|
-
*/
|
|
50
|
-
export function handleHistoryChange(__e: Event) {
|
|
51
|
-
visualTrackFunc();
|
|
52
|
-
setReport();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* 设置信息并触发上报
|
|
57
|
-
*/
|
|
58
|
-
function setReport() {
|
|
59
|
-
let pageUrl = location.href;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 此判断的逻辑是因为spa且hash模式下,路由搜索参数更改也会触发handleHistoryChange事件
|
|
63
|
-
* 所以路由栈中的信息只保存无搜索参数的地址
|
|
64
|
-
*/
|
|
65
|
-
if (Config.hash && Config.spa) {
|
|
66
|
-
const currentUrlSplit = location.href.split('#');
|
|
67
|
-
let currentUrlPostfix = '';
|
|
68
|
-
if (currentUrlSplit[1]) {
|
|
69
|
-
const index = currentUrlSplit[1].indexOf('?');
|
|
70
|
-
if (index > -1) {
|
|
71
|
-
currentUrlPostfix = currentUrlSplit[1].substring(0, index);
|
|
72
|
-
} else {
|
|
73
|
-
currentUrlPostfix = currentUrlSplit[1];
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const currentUrlResult = `${currentUrlSplit[0]}#${currentUrlPostfix}`;
|
|
77
|
-
pageUrl = currentUrlResult;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const { originPage, page } = setRouteStack(pageUrl);
|
|
81
|
-
// 愿页面等于当前页面,说明无路由变更。只有spa且hash模式下才会出现
|
|
82
|
-
if (originPage === page) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const currentTime = new Date().getTime();
|
|
87
|
-
// 页面停留时间
|
|
88
|
-
const stayTime = currentTime - time;
|
|
89
|
-
|
|
90
|
-
// 设置触发路由变化的时间
|
|
91
|
-
time = currentTime;
|
|
92
|
-
// 设置信息
|
|
93
|
-
setReportValue<IReport, 'originPage'>('originPage', originPage);
|
|
94
|
-
setReportValue<IReport, 'page'>('page', page);
|
|
95
|
-
|
|
96
|
-
setReportValue<IReport, 'type'>('type', 'pv');
|
|
97
|
-
setReportValue<IReport, 'pv'>('pv', { stayTime });
|
|
98
|
-
// 上报数据
|
|
99
|
-
report(getReport());
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function setPVTime() {
|
|
103
|
-
time = new Date().getTime();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @description 添加路由栈信息
|
|
108
|
-
* @param page 页面信息
|
|
109
|
-
*/
|
|
110
|
-
export function setRouteStack(page: string | string[]): { originPage: string; page: string } {
|
|
111
|
-
if (typeof page === 'string') {
|
|
112
|
-
routerStack.push(page);
|
|
113
|
-
} else {
|
|
114
|
-
routerStack = routerStack.concat(page);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// 路由栈只需保留两个来作为源页面和当前页面
|
|
118
|
-
routerStack = routerStack.slice(-2);
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
originPage: routerStack[0],
|
|
122
|
-
page: routerStack[1] || routerStack[0],
|
|
123
|
-
};
|
|
124
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: Mark.Zhang
|
|
3
|
-
* @Date: 2020-10-26 11:10:04
|
|
4
|
-
* @Description 用户行为处理方法
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { getElmPath } from '../utils';
|
|
8
|
-
import { report } from '../reporter';
|
|
9
|
-
import { getReport, setReportValue } from '../config/global';
|
|
10
|
-
import { IReport } from '../types/global';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @description 点击事件触发后的操作
|
|
14
|
-
*/
|
|
15
|
-
export function handleClick(event: Event) {
|
|
16
|
-
const target = event.target as HTMLElement;
|
|
17
|
-
if (target.nodeName === 'INPUT' || target.nodeName === 'TEXTAREA') {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const path = getElmPath(target);
|
|
21
|
-
if (path) {
|
|
22
|
-
setReportValue<IReport, 'type'>('type', 'ua');
|
|
23
|
-
setReportValue<IReport, 'ua'>('ua', {
|
|
24
|
-
subType: 'ui.click',
|
|
25
|
-
x: (event as MouseEvent).x,
|
|
26
|
-
y: (event as MouseEvent).y,
|
|
27
|
-
path,
|
|
28
|
-
});
|
|
29
|
-
report(getReport());
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @description 点击触发失焦后的操作
|
|
35
|
-
*/
|
|
36
|
-
export function handleBlur(event: Event) {
|
|
37
|
-
const target = event.target as any;
|
|
38
|
-
|
|
39
|
-
if (target.nodeName !== 'INPUT' && target.nodeName !== 'TEXTAREA') {
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
const path = getElmPath(target);
|
|
43
|
-
if (path) {
|
|
44
|
-
setReportValue<IReport, 'type'>('type', 'ua');
|
|
45
|
-
setReportValue<IReport, 'ua'>('ua', {
|
|
46
|
-
subType: 'ui.blur',
|
|
47
|
-
x: (event as MouseEvent).x,
|
|
48
|
-
y: (event as MouseEvent).y,
|
|
49
|
-
path,
|
|
50
|
-
value: target.value,
|
|
51
|
-
});
|
|
52
|
-
report(getReport());
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @description 滚动的操作
|
|
58
|
-
*/
|
|
59
|
-
let timeout: NodeJS.Timeout;
|
|
60
|
-
export function handleScroll(_event: Event) {
|
|
61
|
-
clearTimeout(timeout);
|
|
62
|
-
timeout = setTimeout(() => {
|
|
63
|
-
setReportValue<IReport, 'type'>('type', 'ua');
|
|
64
|
-
setReportValue<IReport, 'ua'>('ua', {
|
|
65
|
-
subType: 'ui.scroll',
|
|
66
|
-
});
|
|
67
|
-
report(getReport());
|
|
68
|
-
}, 1000);
|
|
69
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { on, off, visualTrackFunc, initWindowObjectFunction, handleLocationChange } from './utils';
|
|
2
|
-
import { setConfig, Config } from './config';
|
|
3
|
-
import { hackFetch, initReport, recordXMLHttpRequestLog } from './config/global';
|
|
4
|
-
import { pv, error, userActivity } from './handlers';
|
|
5
|
-
import { _history } from './handlers/pv';
|
|
6
|
-
import { IConfig } from './types/config';
|
|
7
|
-
import { shuyunTrackSessionId } from './constant';
|
|
8
|
-
|
|
9
|
-
export default class Track {
|
|
10
|
-
init(config: IConfig) {
|
|
11
|
-
// 是否开启日志收集
|
|
12
|
-
if (!config || !config.enable) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// 没有项目ID,则不监听任何事件
|
|
17
|
-
if (!config.projectID) {
|
|
18
|
-
// eslint-disable-next-line no-console
|
|
19
|
-
console.warn('缺少项目ID或token!');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// 没有reportUrl
|
|
24
|
-
if (!config.reportUrl) {
|
|
25
|
-
// eslint-disable-next-line no-console
|
|
26
|
-
console.warn('缺少上报地址!');
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (this.ignoreUrl(config?.ignore?.urls || [])) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
setConfig(config);
|
|
34
|
-
initReport();
|
|
35
|
-
|
|
36
|
-
recordXMLHttpRequestLog(config.XMLHttpRequestTimeout);
|
|
37
|
-
hackFetch(config.XMLHttpRequestTimeout);
|
|
38
|
-
|
|
39
|
-
Config.spa && this.addListenRouterChange();
|
|
40
|
-
|
|
41
|
-
Config.enableBehavior && this.addListenUserActivity();
|
|
42
|
-
|
|
43
|
-
Config.enableError && this.addListenJSUncaught();
|
|
44
|
-
|
|
45
|
-
this.visualTrack();
|
|
46
|
-
|
|
47
|
-
this.addListenUnload();
|
|
48
|
-
initWindowObjectFunction();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
visualTrack = () => {
|
|
52
|
-
window.onload = () => {
|
|
53
|
-
visualTrackFunc();
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @description 监听错误异常
|
|
59
|
-
*/
|
|
60
|
-
addListenJSUncaught() {
|
|
61
|
-
on('error', error.handleError);
|
|
62
|
-
on('unhandledrejection', error.handleError);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* @description 监听行为
|
|
67
|
-
*/
|
|
68
|
-
addListenUserActivity() {
|
|
69
|
-
on('click', userActivity.handleClick); // 非输入框点击
|
|
70
|
-
on('blur', userActivity.handleBlur); // 输入框失焦
|
|
71
|
-
on('scroll', userActivity.handleScroll); // 输入框失焦
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @description 监听路由变化
|
|
76
|
-
*/
|
|
77
|
-
addListenRouterChange() {
|
|
78
|
-
on('popstate', handleLocationChange);
|
|
79
|
-
// on('hashchange', pv.handleHashChange); //触发hashchange的同时也会触发popstate
|
|
80
|
-
if (Config.spa && !Config.hash) {
|
|
81
|
-
history.pushState = _history('pushState');
|
|
82
|
-
history.replaceState = _history('replaceState');
|
|
83
|
-
on('pushState', handleLocationChange);
|
|
84
|
-
on('replaceState', handleLocationChange);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @description 页面将要关闭
|
|
90
|
-
*/
|
|
91
|
-
addListenUnload() {
|
|
92
|
-
on('beforeunload', () => {
|
|
93
|
-
this.destroy();
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* 忽略的url
|
|
99
|
-
* @param urls
|
|
100
|
-
*/
|
|
101
|
-
ignoreUrl(urls: string[]) {
|
|
102
|
-
const someUrl = urls.some((url) => location.href.includes(url));
|
|
103
|
-
return someUrl;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @description 销毁监听器
|
|
108
|
-
*/
|
|
109
|
-
destroy() {
|
|
110
|
-
if (Config.spa) {
|
|
111
|
-
// off('hashchange', pv.handleHashChange);
|
|
112
|
-
off('pushState', pv.handleHistoryChange);
|
|
113
|
-
off('popstate', pv.handleHistoryChange);
|
|
114
|
-
off('replaceState', pv.handleHistoryChange);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (Config.enableBehavior) {
|
|
118
|
-
off('click', userActivity.handleClick);
|
|
119
|
-
off('blur', userActivity.handleBlur);
|
|
120
|
-
off('scroll', userActivity.handleScroll);
|
|
121
|
-
}
|
|
122
|
-
if (Config.enableError) {
|
|
123
|
-
off('error', error.handleError);
|
|
124
|
-
}
|
|
125
|
-
sessionStorage.removeItem(shuyunTrackSessionId);
|
|
126
|
-
}
|
|
127
|
-
}
|