@qiu_jun/monitors 0.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.
Files changed (49) hide show
  1. package/README.md +90 -0
  2. package/dist/exception/index.d.ts +3 -0
  3. package/dist/exception/index.js +9 -0
  4. package/dist/exception/reporter.d.ts +18 -0
  5. package/dist/exception/reporter.js +106 -0
  6. package/dist/exception/transport.d.ts +3 -0
  7. package/dist/exception/transport.js +16 -0
  8. package/dist/exception/types.d.ts +33 -0
  9. package/dist/exception/types.js +6 -0
  10. package/dist/h5.d.ts +4 -0
  11. package/dist/h5.js +11 -0
  12. package/dist/index.d.ts +4 -0
  13. package/dist/index.js +13 -0
  14. package/dist/interface/index.d.ts +83 -0
  15. package/dist/interface/index.js +2 -0
  16. package/dist/modules/err.d.ts +1 -0
  17. package/dist/modules/err.js +91 -0
  18. package/dist/modules/index.d.ts +5 -0
  19. package/dist/modules/index.js +16 -0
  20. package/dist/modules/longTask.d.ts +1 -0
  21. package/dist/modules/longTask.js +27 -0
  22. package/dist/modules/paint.d.ts +1 -0
  23. package/dist/modules/paint.js +61 -0
  24. package/dist/modules/timing.d.ts +1 -0
  25. package/dist/modules/timing.js +42 -0
  26. package/dist/modules/xhr.d.ts +1 -0
  27. package/dist/modules/xhr.js +81 -0
  28. package/dist/monitor.d.ts +43 -0
  29. package/dist/monitor.js +176 -0
  30. package/dist/monitor.umd.js +1 -0
  31. package/dist/reporter.d.ts +3 -0
  32. package/dist/reporter.js +9 -0
  33. package/dist/utils/checkWhiteScreen.d.ts +1 -0
  34. package/dist/utils/checkWhiteScreen.js +42 -0
  35. package/dist/utils/formatStack.d.ts +1 -0
  36. package/dist/utils/formatStack.js +17 -0
  37. package/dist/utils/getLastEvent.d.ts +2 -0
  38. package/dist/utils/getLastEvent.js +29 -0
  39. package/dist/utils/getLogBaseData.d.ts +5 -0
  40. package/dist/utils/getLogBaseData.js +19 -0
  41. package/dist/utils/getSelector.d.ts +1 -0
  42. package/dist/utils/getSelector.js +45 -0
  43. package/dist/utils/index.d.ts +7 -0
  44. package/dist/utils/index.js +22 -0
  45. package/dist/utils/parseQueryString.d.ts +1 -0
  46. package/dist/utils/parseQueryString.js +12 -0
  47. package/dist/utils/toExcEvent.d.ts +8 -0
  48. package/dist/utils/toExcEvent.js +149 -0
  49. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @qiu_jun/monitor
2
+
3
+ 前端监控 SDK:采集异常 + 性能指标,上报至异常分析平台(main-server `/api/exception/report`)。
4
+
5
+ 内置 reporter(与 main-server `exception-sdk` 协议对齐),**无外部 SDK 依赖**,可独立打包发布 npm。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ pnpm add @qiu_jun/monitor
11
+ ```
12
+
13
+ ## 按需引入(子路径导出)
14
+
15
+ 与异常平台 SDK 相同风格,按场景引入:
16
+
17
+ ```ts
18
+ // 完整 H5 监控(采集 + 上报)
19
+ import { Monitor } from '@qiu_jun/monitor'
20
+ import { Monitor } from '@qiu_jun/monitor/h5'
21
+
22
+ // 仅 reporter(自定义采集,复用上报协议)
23
+ import { createReporter, makeH5Transport } from '@qiu_jun/monitor/reporter'
24
+ ```
25
+
26
+ ## 快速接入
27
+
28
+ ```ts
29
+ import { Monitor } from '@qiu_jun/monitor'
30
+
31
+ const monitor = new Monitor({
32
+ endpoint: 'https://your-host/api/exception/report',
33
+ projectKey: 'your-project-key',
34
+ release: '1.0.0', // 客户端版本号 选填
35
+ environment: 'production',
36
+ userId: 'optional-user-id', // 选填
37
+ })
38
+ ```
39
+
40
+ 配置 `endpoint` + `projectKey` 后,所有采集数据自动转为异常平台格式并批量上报。
41
+
42
+ **采样率**:仅在后台「接入项目」里配置 `sampleRate`,客户端无需传。
43
+
44
+ 完整参数说明见 [docs.md](./docs.md)。
45
+
46
+ ## 自动采集
47
+
48
+ | 采集项 | 异常平台 type | 说明 |
49
+ |---|---|---|
50
+ | JS 错误 | `error` | 含选择器、白屏检测 |
51
+ | Promise 未捕获 | `unhandledrejection` | |
52
+ | 资源加载失败 | `resource` | img/script/css 等 |
53
+ | XHR 失败/超时 | `request` | message 格式 `Request failed [500]: GET /api/...` |
54
+ | FP/FCP/FMP/LCP | `paint` | 指标在 `device` |
55
+ | DOMContentLoaded/load | `timing` | |
56
+ | 长任务 | `longTask` | duration ≥ 100ms 时 level=WARN |
57
+
58
+ ## 手动上报
59
+
60
+ ```ts
61
+ monitor.capture({
62
+ type: 'custom',
63
+ level: 'WARN',
64
+ message: '支付回调超时',
65
+ })
66
+ ```
67
+
68
+ ## 构建发布
69
+
70
+ ```bash
71
+ pnpm build # tsc → dist/*.js + *.d.ts,vite → dist/monitor.umd.js
72
+ npm publish
73
+ ```
74
+
75
+ 产物:
76
+
77
+ | 路径 | 说明 |
78
+ |---|---|
79
+ | `@qiu_jun/monitor` | `dist/index.js` + `dist/index.d.ts` |
80
+ | `@qiu_jun/monitor/h5` | `dist/h5.js` + `dist/h5.d.ts` |
81
+ | `@qiu_jun/monitor/reporter` | `dist/reporter.js` + `dist/reporter.d.ts` |
82
+ | UMD | `dist/monitor.umd.js`(`require` 条件导出) |
83
+
84
+ ## 与 main-server 的关系
85
+
86
+ - 上报协议对齐 `packages/main-server/src/modules/exception/report/`
87
+ - 异常类 → `exc_issue` + `exc_event`
88
+ - 性能类(paint/timing/longTask)→ `exc_perf_event`
89
+ - reporter 源码位于 `src/exception/`,与 exception-sdk 逻辑等价,便于独立发版
90
+ - **后台对接与展示**:[backend-integration.md](./backend-integration.md)(与 exception 模块 `/api/exception/*` 接口一一对照)
@@ -0,0 +1,3 @@
1
+ export { createReporter, ExcReporter, SDK_VERSION } from './reporter';
2
+ export { makeH5Transport } from './transport';
3
+ export type { ExcEventPayload, ExcSdkOptions, ExcTransport } from './types';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeH5Transport = exports.SDK_VERSION = exports.ExcReporter = exports.createReporter = void 0;
4
+ var reporter_1 = require("./reporter");
5
+ Object.defineProperty(exports, "createReporter", { enumerable: true, get: function () { return reporter_1.createReporter; } });
6
+ Object.defineProperty(exports, "ExcReporter", { enumerable: true, get: function () { return reporter_1.ExcReporter; } });
7
+ Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return reporter_1.SDK_VERSION; } });
8
+ var transport_1 = require("./transport");
9
+ Object.defineProperty(exports, "makeH5Transport", { enumerable: true, get: function () { return transport_1.makeH5Transport; } });
@@ -0,0 +1,18 @@
1
+ import type { ExcEventPayload, ExcSdkOptions, ExcTransport } from './types';
2
+ export declare const SDK_VERSION = "0.0.1";
3
+ /** 缓冲上报器:攒批 → transport 批量上报 */
4
+ export declare class ExcReporter {
5
+ private readonly options;
6
+ private readonly transport;
7
+ private buffer;
8
+ private timer;
9
+ private sending;
10
+ constructor(options: ExcSdkOptions, transport: ExcTransport);
11
+ /** 采样 + 入缓冲 */
12
+ capture(event: ExcEventPayload): void;
13
+ flush(): Promise<void>;
14
+ destroy(): void;
15
+ private ensureTimer;
16
+ private clearTimer;
17
+ }
18
+ export declare function createReporter(options: ExcSdkOptions, transport: ExcTransport): ExcReporter;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExcReporter = exports.SDK_VERSION = void 0;
4
+ exports.createReporter = createReporter;
5
+ exports.SDK_VERSION = '0.0.1';
6
+ const DEFAULT_MAX_BATCH = 20;
7
+ const DEFAULT_FLUSH_INTERVAL = 30000;
8
+ const MAX_BUFFER = 100;
9
+ /** 缓冲上报器:攒批 → transport 批量上报 */
10
+ class ExcReporter {
11
+ constructor(options, transport) {
12
+ Object.defineProperty(this, "options", {
13
+ enumerable: true,
14
+ configurable: true,
15
+ writable: true,
16
+ value: options
17
+ });
18
+ Object.defineProperty(this, "transport", {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value: transport
23
+ });
24
+ Object.defineProperty(this, "buffer", {
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true,
28
+ value: []
29
+ });
30
+ Object.defineProperty(this, "timer", {
31
+ enumerable: true,
32
+ configurable: true,
33
+ writable: true,
34
+ value: null
35
+ });
36
+ Object.defineProperty(this, "sending", {
37
+ enumerable: true,
38
+ configurable: true,
39
+ writable: true,
40
+ value: false
41
+ });
42
+ }
43
+ /** 采样 + 入缓冲 */
44
+ capture(event) {
45
+ var _a, _b, _c, _d, _e;
46
+ const sampleRate = (_a = this.options.sampleRate) !== null && _a !== void 0 ? _a : 100;
47
+ if (sampleRate < 100 && Math.random() * 100 >= sampleRate)
48
+ return;
49
+ this.buffer.push({
50
+ ...event,
51
+ level: (_b = event.level) !== null && _b !== void 0 ? _b : 'ERROR',
52
+ occurredAt: (_c = event.occurredAt) !== null && _c !== void 0 ? _c : new Date().toISOString(),
53
+ sdkVersion: (_d = event.sdkVersion) !== null && _d !== void 0 ? _d : exports.SDK_VERSION,
54
+ });
55
+ if (this.buffer.length > MAX_BUFFER)
56
+ this.buffer = this.buffer.slice(-MAX_BUFFER);
57
+ if (this.buffer.length >= ((_e = this.options.maxBatch) !== null && _e !== void 0 ? _e : DEFAULT_MAX_BATCH))
58
+ void this.flush();
59
+ else
60
+ this.ensureTimer();
61
+ }
62
+ async flush() {
63
+ if (this.sending || this.buffer.length === 0)
64
+ return;
65
+ this.clearTimer();
66
+ this.sending = true;
67
+ const events = this.buffer;
68
+ this.buffer = [];
69
+ try {
70
+ await this.transport({ events }, this.options.projectKey);
71
+ }
72
+ catch (err) {
73
+ // 403 key 无效:放弃;其余放回缓冲重试
74
+ if ((err === null || err === void 0 ? void 0 : err.statusCode) !== 403) {
75
+ this.buffer = [...events, ...this.buffer].slice(-MAX_BUFFER);
76
+ this.ensureTimer();
77
+ }
78
+ }
79
+ finally {
80
+ this.sending = false;
81
+ }
82
+ }
83
+ destroy() {
84
+ this.clearTimer();
85
+ void this.flush();
86
+ }
87
+ ensureTimer() {
88
+ var _a;
89
+ if (this.timer)
90
+ return;
91
+ this.timer = setTimeout(() => {
92
+ this.timer = null;
93
+ void this.flush();
94
+ }, (_a = this.options.flushInterval) !== null && _a !== void 0 ? _a : DEFAULT_FLUSH_INTERVAL);
95
+ }
96
+ clearTimer() {
97
+ if (this.timer) {
98
+ clearTimeout(this.timer);
99
+ this.timer = null;
100
+ }
101
+ }
102
+ }
103
+ exports.ExcReporter = ExcReporter;
104
+ function createReporter(options, transport) {
105
+ return new ExcReporter(options, transport);
106
+ }
@@ -0,0 +1,3 @@
1
+ import type { ExcTransport } from './types';
2
+ /** H5 transport:fetch + keepalive(页面卸载时仍可发出) */
3
+ export declare function makeH5Transport(endpoint: string): ExcTransport;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeH5Transport = makeH5Transport;
4
+ /** H5 transport:fetch + keepalive(页面卸载时仍可发出) */
5
+ function makeH5Transport(endpoint) {
6
+ return async (payload, projectKey) => {
7
+ const res = await fetch(endpoint, {
8
+ method: 'POST',
9
+ headers: { 'content-type': 'application/json', 'X-Project-Key': projectKey },
10
+ body: JSON.stringify(payload),
11
+ keepalive: true,
12
+ });
13
+ if (!res.ok)
14
+ throw Object.assign(new Error(`monitor: 上报失败 ${res.status}`), { statusCode: res.status });
15
+ };
16
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 与 main-server packages/exception-sdk/src/types.ts 对齐
3
+ * monitor 内置 reporter,避免跨仓库 dist 依赖
4
+ */
5
+ /** SDK 配置 */
6
+ export interface ExcSdkOptions {
7
+ endpoint: string;
8
+ projectKey: string;
9
+ release?: string;
10
+ environment?: string;
11
+ sampleRate?: number;
12
+ maxBatch?: number;
13
+ flushInterval?: number;
14
+ }
15
+ /** 单条上报事件(对齐服务端 ReportEventDto) */
16
+ export interface ExcEventPayload {
17
+ type: 'error' | 'unhandledrejection' | 'resource' | 'request' | 'custom' | 'paint' | 'timing' | 'longTask';
18
+ level?: 'FATAL' | 'ERROR' | 'WARN' | 'INFO';
19
+ message: string;
20
+ stack?: string;
21
+ page?: string;
22
+ userId?: string;
23
+ /** 客户端版本号 */
24
+ release?: string;
25
+ /** 环境 production | development */
26
+ environment?: string;
27
+ sdkVersion?: string;
28
+ occurredAt?: string;
29
+ device?: Record<string, any>;
30
+ }
31
+ export type ExcTransport = (payload: {
32
+ events: ExcEventPayload[];
33
+ }, projectKey: string) => Promise<void>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * 与 main-server packages/exception-sdk/src/types.ts 对齐
4
+ * monitor 内置 reporter,避免跨仓库 dist 依赖
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/h5.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /** H5 监控入口(按需引入,与主入口能力相同) */
2
+ export { default as Monitor } from './monitor';
3
+ export { default } from './monitor';
4
+ export type * from './interface';
package/dist/h5.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = exports.Monitor = void 0;
7
+ /** H5 监控入口(按需引入,与主入口能力相同) */
8
+ var monitor_1 = require("./monitor");
9
+ Object.defineProperty(exports, "Monitor", { enumerable: true, get: function () { return __importDefault(monitor_1).default; } });
10
+ var monitor_2 = require("./monitor");
11
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(monitor_2).default; } });
@@ -0,0 +1,4 @@
1
+ export { default as Monitor } from './monitor';
2
+ export type * from './interface';
3
+ export { createReporter, makeH5Transport, ExcReporter, SDK_VERSION } from './exception';
4
+ export type { ExcEventPayload, ExcSdkOptions, ExcTransport } from './exception';
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SDK_VERSION = exports.ExcReporter = exports.makeH5Transport = exports.createReporter = exports.Monitor = void 0;
7
+ var monitor_1 = require("./monitor");
8
+ Object.defineProperty(exports, "Monitor", { enumerable: true, get: function () { return __importDefault(monitor_1).default; } });
9
+ var exception_1 = require("./exception");
10
+ Object.defineProperty(exports, "createReporter", { enumerable: true, get: function () { return exception_1.createReporter; } });
11
+ Object.defineProperty(exports, "makeH5Transport", { enumerable: true, get: function () { return exception_1.makeH5Transport; } });
12
+ Object.defineProperty(exports, "ExcReporter", { enumerable: true, get: function () { return exception_1.ExcReporter; } });
13
+ Object.defineProperty(exports, "SDK_VERSION", { enumerable: true, get: function () { return exception_1.SDK_VERSION; } });
@@ -0,0 +1,83 @@
1
+ export interface IMonitorOptions {
2
+ /** 异常平台上报地址,如 https://host/api/exception/report */
3
+ endpoint: string;
4
+ /** 接入项目 projectKey(后台「接入项目」创建后获得) */
5
+ projectKey: string;
6
+ /** 客户端版本号 */
7
+ release?: string;
8
+ /** 环境 production | development */
9
+ environment?: string;
10
+ /** reporter 批量阈值,默认 20 */
11
+ maxBatch?: number;
12
+ /** reporter 定时 flush 间隔 ms,默认 30000(30 秒) */
13
+ flushInterval?: number;
14
+ userId?: string;
15
+ /** XHR 超时阈值 ms,默认 60000(1 分钟) */
16
+ timeoutDuration?: number;
17
+ maxQueueSize?: number;
18
+ }
19
+ export interface BaseLog {
20
+ title: string;
21
+ url: string;
22
+ userAgent: string;
23
+ browser: string;
24
+ device: string;
25
+ os: string;
26
+ }
27
+ export interface ErrorLog {
28
+ type: "error";
29
+ errorType: "jsError" | "promiseError" | "loadResourceError" | "xhrError";
30
+ message: string;
31
+ filename?: string;
32
+ position?: string;
33
+ stack?: string;
34
+ selector?: string;
35
+ isWhiteScreen?: boolean;
36
+ tagName?: string;
37
+ xhrData?: {
38
+ eventType: "load" | "error";
39
+ url: string;
40
+ method: string;
41
+ header: Record<string, unknown>;
42
+ params: string;
43
+ duration: number;
44
+ status: number;
45
+ response: string;
46
+ };
47
+ }
48
+ export interface PaintLog {
49
+ type: "paint";
50
+ FP?: number;
51
+ FCP?: number;
52
+ FMP?: number;
53
+ LCP?: number;
54
+ }
55
+ export interface TimingLog {
56
+ type: "timing";
57
+ DOMContentLoadedTime: number;
58
+ loadTime: number;
59
+ }
60
+ export interface LongTaskLog {
61
+ type: "longTask";
62
+ startTime: number;
63
+ duration: number;
64
+ eventType?: string;
65
+ selector?: string;
66
+ }
67
+ export interface RequestLog {
68
+ type: "xhr" | "fetch";
69
+ startTime: number;
70
+ duration: number;
71
+ msg: string;
72
+ success?: boolean;
73
+ status?: number;
74
+ url?: string;
75
+ method?: string;
76
+ /** 请求发生时页面地址(captureRequest 自动填充) */
77
+ page?: string;
78
+ }
79
+ export interface BatchRequestLog {
80
+ type: 'batchXHR';
81
+ requests: RequestLog[];
82
+ }
83
+ export type MonitorTypeLog = ErrorLog | PaintLog | TimingLog | LongTaskLog | RequestLog | BatchRequestLog;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export default function onWindowErr(): void;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = onWindowErr;
4
+ const utils_1 = require("../utils");
5
+ function onWindowErr() {
6
+ window.addEventListener('error', event => {
7
+ console.log("error event: ", event);
8
+ // 监听 JS/CSS 资源文件加载错误
9
+ const target = event.target;
10
+ let filename;
11
+ if (target &&
12
+ (filename =
13
+ target.src || target.href)) {
14
+ // 1、数据建模存储
15
+ const log = {
16
+ type: "error",
17
+ errorType: "loadResourceError", // 错误类型 - JS/CSS 资源加载错误
18
+ message: `${filename} resource loading fail.`,
19
+ filename, // 报错的文件
20
+ tagName: target.tagName, // 资源标签名称
21
+ // body script
22
+ selector: (0, utils_1.getSelector)(event.target),
23
+ };
24
+ console.log("log: ", log);
25
+ // 2、上报数据
26
+ // @ts-ignore
27
+ this.send(log);
28
+ }
29
+ else {
30
+ // 监听 JS 代码执行出错
31
+ const lastEvent = (0, utils_1.getLastEvent)(); // 监听到错误后,获取到最后一个交互事件
32
+ const isWhiteScreen = (0, utils_1.checkWhiteScreen)(); // 检查是否白屏
33
+ // 1.1、数据建模存储
34
+ const errorLog = {
35
+ // kind: "stability", // 监控指标的大类
36
+ type: "error",
37
+ errorType: "jsError",
38
+ message: event.message,
39
+ filename: event.filename,
40
+ position: `${event.lineno}:${event.colno}`,
41
+ stack: (0, utils_1.formatStack)(event.error.stack),
42
+ selector: lastEvent ? (0, utils_1.getSelector)() : "",
43
+ isWhiteScreen,
44
+ };
45
+ console.log("js error log: ", errorLog);
46
+ // 1.2、上报数据
47
+ // @ts-ignore
48
+ this.send(errorLog);
49
+ }
50
+ }, true);
51
+ // promise
52
+ window.addEventListener('unhandledrejection', event => {
53
+ console.log("Promise error event: ", event);
54
+ const lastEvent = (0, utils_1.getLastEvent)(); // 监听到错误后,获取到最后一个交互事件
55
+ let message;
56
+ const reason = event.reason; // Promise 失败的原因
57
+ let filename;
58
+ let line = 0;
59
+ let column = 0;
60
+ let stack = "";
61
+ if (typeof event.reason === "string") {
62
+ // 情况 1、是 Promise reject 抛出的错误(没有办法获取 stack 等信息)
63
+ message = reason;
64
+ }
65
+ else if (typeof reason === "object") {
66
+ message = reason.message;
67
+ // 情况 2、是 Promise 中 JS 代码执行出错
68
+ if (reason.stack) {
69
+ const matchResult = reason.stack.match(/at\s+(.+):(\d+):(\d+)/);
70
+ filename = matchResult[1];
71
+ line = matchResult[2];
72
+ column = matchResult[3];
73
+ stack = (0, utils_1.formatStack)(reason.stack);
74
+ }
75
+ }
76
+ // 2.1、数据建模存储
77
+ const errorLog = {
78
+ type: "error",
79
+ errorType: "promiseError", // 错误类型 - Promise 代码错误
80
+ message,
81
+ filename,
82
+ position: `${line}:${column}`,
83
+ stack,
84
+ selector: lastEvent ? (0, utils_1.getSelector)() : "",
85
+ };
86
+ console.log("promise error log: ", errorLog);
87
+ // 2.2、上报数据
88
+ // @ts-ignore
89
+ this.send(errorLog);
90
+ }, true);
91
+ }
@@ -0,0 +1,5 @@
1
+ export { default as onWindowErr } from './err';
2
+ export { default as onLongTask } from './longTask';
3
+ export { default as onPaint } from './paint';
4
+ export { default as onTiming } from './timing';
5
+ export { default as onXHR } from './xhr';
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.onXHR = exports.onTiming = exports.onPaint = exports.onLongTask = exports.onWindowErr = void 0;
7
+ var err_1 = require("./err");
8
+ Object.defineProperty(exports, "onWindowErr", { enumerable: true, get: function () { return __importDefault(err_1).default; } });
9
+ var longTask_1 = require("./longTask");
10
+ Object.defineProperty(exports, "onLongTask", { enumerable: true, get: function () { return __importDefault(longTask_1).default; } });
11
+ var paint_1 = require("./paint");
12
+ Object.defineProperty(exports, "onPaint", { enumerable: true, get: function () { return __importDefault(paint_1).default; } });
13
+ var timing_1 = require("./timing");
14
+ Object.defineProperty(exports, "onTiming", { enumerable: true, get: function () { return __importDefault(timing_1).default; } });
15
+ var xhr_1 = require("./xhr");
16
+ Object.defineProperty(exports, "onXHR", { enumerable: true, get: function () { return __importDefault(xhr_1).default; } });
@@ -0,0 +1 @@
1
+ export default function onLongTask(): void;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = onLongTask;
4
+ const utils_1 = require("../utils");
5
+ function onLongTask() {
6
+ if (PerformanceObserver) {
7
+ const observerLongTask = new PerformanceObserver(list => {
8
+ list.getEntries().forEach(entry => {
9
+ // 执行时长大于 100 ms
10
+ if (entry.duration > 100) {
11
+ const lastEvent = (0, utils_1.getLastEvent)();
12
+ const log = {
13
+ type: "longTask",
14
+ startTime: entry.startTime, // 开始时间
15
+ duration: entry.duration, // 持续时间
16
+ selector: lastEvent ? (0, utils_1.getSelector)() : "",
17
+ eventType: lastEvent === null || lastEvent === void 0 ? void 0 : lastEvent.type,
18
+ };
19
+ console.log("longTask log: ", log);
20
+ // @ts-ignore
21
+ this.send(log);
22
+ }
23
+ });
24
+ });
25
+ observerLongTask.observe({ entryTypes: ["longtask"] });
26
+ }
27
+ }
@@ -0,0 +1 @@
1
+ export default function onPaint(): void;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = onPaint;
4
+ function onPaint() {
5
+ if (PerformanceObserver) {
6
+ let FP = null;
7
+ let FCP = null;
8
+ let FMP = null;
9
+ let LCP = null;
10
+ // 1、监控性能指标 FP(First Paint) 和 FCP(First Contentful Paint)
11
+ const observerFPAndFCP = new PerformanceObserver(function (entryList) {
12
+ const perfEntries = entryList.getEntries();
13
+ for (const perfEntry of perfEntries) {
14
+ if (perfEntry.name === "first-paint") {
15
+ FP = perfEntry;
16
+ console.log("首次像素绘制 时间:", FP === null || FP === void 0 ? void 0 : FP.startTime);
17
+ }
18
+ else if (perfEntry.name === "first-contentful-paint") {
19
+ FCP = perfEntry;
20
+ console.log("首次内容绘制 时间:", FCP === null || FCP === void 0 ? void 0 : FCP.startTime);
21
+ observerFPAndFCP.disconnect(); // 得到 FCP 后,断开观察,不再观察了
22
+ }
23
+ }
24
+ });
25
+ // 观察 paint 相关性能指标
26
+ observerFPAndFCP.observe({ entryTypes: ["paint"] });
27
+ // 2、监控性能指标:FMP(First Meaningful Paint)
28
+ const observerFMP = new PerformanceObserver(entryList => {
29
+ const perfEntries = entryList.getEntries();
30
+ FMP = perfEntries[0];
31
+ console.log("首次有意义元素绘制 时间:", FMP === null || FMP === void 0 ? void 0 : FMP.startTime);
32
+ observerFMP.disconnect(); // 断开观察,不再观察了
33
+ });
34
+ observerFMP.observe({ entryTypes: ["element"] });
35
+ // 3、创建性能观察者,观察 LCP
36
+ const observerLCP = new PerformanceObserver(entryList => {
37
+ const perfEntries = entryList.getEntries();
38
+ LCP = perfEntries[0];
39
+ console.log("最大内容绘制 时间:", LCP === null || LCP === void 0 ? void 0 : LCP.startTime, perfEntries);
40
+ });
41
+ // 观察页面中最大内容的绘制
42
+ observerLCP.observe({ entryTypes: ["largest-contentful-paint"] });
43
+ // 上送性能指标
44
+ window.addEventListener("load", () => {
45
+ setTimeout(() => {
46
+ // 在上报性能指标数据的时候,停止 LCP 的观察。
47
+ observerLCP.disconnect();
48
+ const log = {
49
+ type: "paint",
50
+ FP: FP === null || FP === void 0 ? void 0 : FP.startTime, // FP
51
+ FCP: FCP === null || FCP === void 0 ? void 0 : FCP.startTime, // FCP
52
+ FMP: FMP === null || FMP === void 0 ? void 0 : FMP.startTime, // FMP
53
+ LCP: LCP === null || LCP === void 0 ? void 0 : LCP.startTime, // LCP
54
+ };
55
+ console.log("paint log: ", log);
56
+ // @ts-ignore
57
+ this.send(log);
58
+ }, 3000);
59
+ });
60
+ }
61
+ }
@@ -0,0 +1 @@
1
+ export default function onTiming(): void;