@lark-sentry/core 1.0.0 → 1.0.1
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 +104 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +105 -67
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +5 -5
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.js +5 -5
- package/dist/index.min.js.map +1 -1
- package/index.ts +70 -0
- package/package.json +5 -21
- package/package.prod.json +39 -0
- package/src/breadcrumb.ts +26 -0
- package/src/bus.ts +31 -0
- package/src/decorate-publish.ts +276 -0
- package/src/handlers.ts +230 -0
- package/src/setup.ts +48 -0
- package/src/white-screen.ts +146 -0
package/src/setup.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EventType,
|
|
3
|
+
type TEventHandler,
|
|
4
|
+
type TReportPayload,
|
|
5
|
+
} from "@lark-sentry/types";
|
|
6
|
+
|
|
7
|
+
import { sub } from "./bus.js";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
handleClick,
|
|
11
|
+
handleError,
|
|
12
|
+
handleHashChange,
|
|
13
|
+
handleHistory,
|
|
14
|
+
handleHttp,
|
|
15
|
+
handleUnhandledRejection,
|
|
16
|
+
handleWhiteScreen,
|
|
17
|
+
} from "./handlers.js";
|
|
18
|
+
|
|
19
|
+
import decoratePublish from "./decorate-publish.js";
|
|
20
|
+
|
|
21
|
+
type THandler = TEventHandler<TReportPayload>;
|
|
22
|
+
function setup() {
|
|
23
|
+
sub(EventType.Xhr, handleHttp as THandler);
|
|
24
|
+
decoratePublish(EventType.Xhr);
|
|
25
|
+
|
|
26
|
+
sub(EventType.Fetch, handleHttp as THandler);
|
|
27
|
+
decoratePublish(EventType.Fetch);
|
|
28
|
+
|
|
29
|
+
sub(EventType.Error, handleError as THandler);
|
|
30
|
+
decoratePublish(EventType.Error);
|
|
31
|
+
|
|
32
|
+
sub(EventType.History, handleHistory as THandler);
|
|
33
|
+
decoratePublish(EventType.History);
|
|
34
|
+
|
|
35
|
+
sub(EventType.HashChange, handleHashChange as THandler);
|
|
36
|
+
decoratePublish(EventType.HashChange);
|
|
37
|
+
|
|
38
|
+
sub(EventType.UnhandledRejection, handleUnhandledRejection as THandler);
|
|
39
|
+
decoratePublish(EventType.UnhandledRejection);
|
|
40
|
+
|
|
41
|
+
sub(EventType.Click, handleClick as THandler);
|
|
42
|
+
decoratePublish(EventType.Click);
|
|
43
|
+
|
|
44
|
+
sub(EventType.WhiteScreen, handleWhiteScreen as THandler);
|
|
45
|
+
decoratePublish(EventType.WhiteScreen);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default setup;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_WHITE_SCREEN_SAMPLE_COUNT,
|
|
3
|
+
WHITE_SCREEN_SAMPLE_INTERVAL,
|
|
4
|
+
} from "@lark-sentry/constants";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
EventType,
|
|
8
|
+
Status,
|
|
9
|
+
type IBaseDataWithEvent,
|
|
10
|
+
type TOnReportWhiteScreenData,
|
|
11
|
+
} from "@lark-sentry/types";
|
|
12
|
+
|
|
13
|
+
import { sentry, getCssSelectors, getBaseData } from "@lark-sentry/utils";
|
|
14
|
+
|
|
15
|
+
function checkWhiteScreen(onReport: TOnReportWhiteScreenData) {
|
|
16
|
+
const { hasSkeleton, rootCssSelectors } = sentry.options;
|
|
17
|
+
let sampleCount = 0;
|
|
18
|
+
const initialSelectors = new Set<string>();
|
|
19
|
+
const currentSelectors = new Set<string>();
|
|
20
|
+
|
|
21
|
+
const isRoot = (elem: Element) => {
|
|
22
|
+
const selectors = getCssSelectors(elem);
|
|
23
|
+
const [idSelector, classSelector, elementSelector] = selectors;
|
|
24
|
+
if (hasSkeleton) {
|
|
25
|
+
if (sampleCount === 1) {
|
|
26
|
+
selectors.forEach((selector) => initialSelectors.add(selector));
|
|
27
|
+
} else {
|
|
28
|
+
selectors.forEach((selector) => currentSelectors.add(selector));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return (
|
|
32
|
+
rootCssSelectors.includes(idSelector) ||
|
|
33
|
+
rootCssSelectors.includes(classSelector) ||
|
|
34
|
+
rootCssSelectors.includes(elementSelector)
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const sample = () => {
|
|
39
|
+
sampleCount++;
|
|
40
|
+
if (hasSkeleton && sampleCount > 0) {
|
|
41
|
+
currentSelectors.clear();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (sampleCount > MAX_WHITE_SCREEN_SAMPLE_COUNT) {
|
|
45
|
+
stopSample();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { innerWidth, innerHeight } = globalThis;
|
|
50
|
+
let emptyPoints = 0;
|
|
51
|
+
for (let i = 1; i <= 9; i++) {
|
|
52
|
+
const rowElem = document.elementFromPoint(
|
|
53
|
+
(innerWidth * i) / 10,
|
|
54
|
+
innerHeight / 2,
|
|
55
|
+
);
|
|
56
|
+
const colElem = document.elementFromPoint(
|
|
57
|
+
innerWidth / 2,
|
|
58
|
+
(innerHeight * i) / 10,
|
|
59
|
+
);
|
|
60
|
+
if (!rowElem || isRoot(rowElem)) {
|
|
61
|
+
emptyPoints++;
|
|
62
|
+
}
|
|
63
|
+
if (!colElem || isRoot(colElem)) {
|
|
64
|
+
emptyPoints++;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const isWhiteScreen = emptyPoints >= 18;
|
|
69
|
+
|
|
70
|
+
// 无骨架屏
|
|
71
|
+
if (!hasSkeleton) {
|
|
72
|
+
if (isWhiteScreen) {
|
|
73
|
+
report();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
stopSample();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 有骨架屏
|
|
80
|
+
if (hasSkeleton) {
|
|
81
|
+
// 首次采样
|
|
82
|
+
if (sampleCount === 1) {
|
|
83
|
+
return; // sampling
|
|
84
|
+
}
|
|
85
|
+
// 非首次采样
|
|
86
|
+
if (
|
|
87
|
+
Array.from(currentSelectors).sort().join(",") ===
|
|
88
|
+
Array.from(initialSelectors).sort().join(",")
|
|
89
|
+
) {
|
|
90
|
+
report();
|
|
91
|
+
return; // sampling
|
|
92
|
+
}
|
|
93
|
+
stopSample();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const report = () => {
|
|
98
|
+
const whiteScreenData: IBaseDataWithEvent = {
|
|
99
|
+
...getBaseData(),
|
|
100
|
+
type: EventType.WhiteScreen,
|
|
101
|
+
status: Status.Error,
|
|
102
|
+
name: "WhiteScreen",
|
|
103
|
+
message: `sample count ${sampleCount}`,
|
|
104
|
+
extra: "WhiteScreen",
|
|
105
|
+
};
|
|
106
|
+
onReport(whiteScreenData);
|
|
107
|
+
stopSample();
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const stopSample = () => {
|
|
111
|
+
if (sentry.whiteScreenTimer) {
|
|
112
|
+
clearInterval(sentry.whiteScreenTimer);
|
|
113
|
+
sentry.whiteScreenTimer = null;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const loopSample = () => {
|
|
118
|
+
if (sentry.whiteScreenTimer) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
sentry.whiteScreenTimer = setInterval(() => {
|
|
122
|
+
if ("requestIdleCallback" in globalThis) {
|
|
123
|
+
requestIdleCallback((deadline) => {
|
|
124
|
+
if (deadline.timeRemaining() > 0 || deadline.didTimeout) {
|
|
125
|
+
sample();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
sample();
|
|
130
|
+
}
|
|
131
|
+
}, WHITE_SCREEN_SAMPLE_INTERVAL);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const startSample = () => {
|
|
135
|
+
if (document.readyState === "complete") {
|
|
136
|
+
loopSample();
|
|
137
|
+
} else {
|
|
138
|
+
globalThis.addEventListener("load", loopSample, { once: true });
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
startSample();
|
|
143
|
+
return { stop: stopSample };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default checkWhiteScreen;
|