performance-sdk-web-xiangwang 1.0.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/README.md +255 -0
- package/dist/index.cjs.js +502 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.esm.js +500 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/interaction/FID.d.ts +1 -0
- package/dist/interaction/INP.d.ts +1 -0
- package/dist/interaction/index.d.ts +3 -0
- package/dist/interaction/longtask.d.ts +1 -0
- package/dist/loading/FCP.d.ts +1 -0
- package/dist/loading/FP.d.ts +1 -0
- package/dist/loading/LCP.d.ts +1 -0
- package/dist/loading/index.d.ts +4 -0
- package/dist/loading/load.d.ts +1 -0
- package/dist/network/entries.d.ts +1 -0
- package/dist/network/index.d.ts +2 -0
- package/dist/network/request.d.ts +1 -0
- package/dist/report/index.d.ts +6 -0
- package/dist/util/index.d.ts +5 -0
- package/dist/visualStability/CLS.d.ts +1 -0
- package/dist/visualStability/index.d.ts +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Performance SDK
|
|
2
|
+
|
|
3
|
+
一个轻量的前端性能监控 SDK,开箱即用地采集核心性能指标(Core Web Vitals、资源与网络、交互与长任务、视觉稳定性),并通过 `sendBeacon`(或 `fetch keepalive` 兜底)稳定上报到你的服务端。
|
|
4
|
+
|
|
5
|
+
- 包名:`performance-sdk`
|
|
6
|
+
- 产物:`dist/index.cjs.js`、`dist/index.esm.js`、`dist/index.umd.js`
|
|
7
|
+
- 许可证:MIT
|
|
8
|
+
|
|
9
|
+
## 目录结构
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
performance-monitor/
|
|
13
|
+
├── dist/ # 打包产物
|
|
14
|
+
├── src/ # 源码目录
|
|
15
|
+
│ ├── index.ts # 入口文件
|
|
16
|
+
│ ├── loading/ # 加载与绘制采集(FP/FCP/LCP/Load)
|
|
17
|
+
│ ├── interaction/ # 交互采集(FID/INP/LongTask)
|
|
18
|
+
│ ├── visualStability/ # 视觉稳定性(CLS)
|
|
19
|
+
│ ├── network/ # 资源与请求(ResourceTiming / API 请求)
|
|
20
|
+
│ ├── report/ # 数据上报(sendBeacon / fetch keepalive)
|
|
21
|
+
│ └── util/ # 工具与路由监听(getSelector/onUrlChange)
|
|
22
|
+
├── test/ # 测试靶场
|
|
23
|
+
│ ├── server.js # 本地测试服务
|
|
24
|
+
│ ├── index.html # 指标触发页面
|
|
25
|
+
│ └── case-*.js # 专项示例(cls/interaction/longtask/network)
|
|
26
|
+
├── package.json # 项目配置
|
|
27
|
+
├── rollup.config.js # Rollup 打包配置
|
|
28
|
+
└── tsconfig.json # TypeScript 配置
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 功能概览
|
|
32
|
+
|
|
33
|
+
- 页面加载与渲染:`FP`、`FCP`、`LCP`、`load/pageshow`
|
|
34
|
+
- 交互性能:`FID`、`INP`(事件级交互耗时,含输入延迟/处理/呈现)
|
|
35
|
+
- 长任务监控:`LongTask`(阻塞主线程)
|
|
36
|
+
- 视觉稳定性:`CLS`(累积布局偏移,含来源元素选择器)
|
|
37
|
+
- 资源与网络:`PerformanceResourceTiming`(DNS/TCP/TTFB/大小/协议)
|
|
38
|
+
- 稳定上报:优先 `navigator.sendBeacon`,降级 `fetch keepalive`
|
|
39
|
+
|
|
40
|
+
## 快速开始
|
|
41
|
+
|
|
42
|
+
npm install
|
|
43
|
+
|
|
44
|
+
npm run build (生成 dist 产物文件,可直接引入使用)
|
|
45
|
+
|
|
46
|
+
### 1) 使用 UMD(无打包器)
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<script src="/dist/index.umd.js"></script>
|
|
50
|
+
<script>
|
|
51
|
+
// UMD 全局名:window.PerformanceSDK
|
|
52
|
+
const PerformanceMonitor = window.PerformanceSDK;
|
|
53
|
+
const monitor = new PerformanceMonitor({
|
|
54
|
+
reportUrl: '/api/performance',
|
|
55
|
+
log: true, // 开发环境建议开启;生产关闭
|
|
56
|
+
});
|
|
57
|
+
monitor.init();
|
|
58
|
+
</script>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2) 使用 ESModule 或 CJS(配合打包器)
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// ESM
|
|
65
|
+
import PerformanceMonitor from './dist/index.esm.js';
|
|
66
|
+
|
|
67
|
+
const monitor = new PerformanceMonitor({
|
|
68
|
+
reportUrl: '/api/performance',
|
|
69
|
+
log: false,
|
|
70
|
+
});
|
|
71
|
+
monitor.init();
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
// CJS
|
|
76
|
+
const PerformanceMonitor = require('./dist/index.cjs.js');
|
|
77
|
+
|
|
78
|
+
const monitor = new PerformanceMonitor({
|
|
79
|
+
reportUrl: '/api/performance',
|
|
80
|
+
log: false,
|
|
81
|
+
});
|
|
82
|
+
monitor.init();
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## 配置项
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
new PerformanceMonitor({
|
|
89
|
+
// 是否在控制台输出调试日志(CLS 源等)
|
|
90
|
+
log: true, // 默认 true
|
|
91
|
+
|
|
92
|
+
// 数据上报地址
|
|
93
|
+
reportUrl: '/api/performance', // 默认 /api/performance
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 指标说明与上报数据
|
|
98
|
+
|
|
99
|
+
SDK 所有上报都会自动追加公共字段:
|
|
100
|
+
`userAgent`、`timestamp`。以下为主要指标结构(示例):
|
|
101
|
+
|
|
102
|
+
- 渲染类(`FP`、`FCP`、`LCP`)
|
|
103
|
+
- 共同字段:`type: 'performance'`、`name`、`startTime`、`pageUrl`
|
|
104
|
+
- `LCP` 额外:`lcpTime`(= `startTime`)、`elementSelector`
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"type": "performance",
|
|
109
|
+
"name": "first-contentful-paint",
|
|
110
|
+
"startTime": 123.45,
|
|
111
|
+
"pageUrl": "https://example.com",
|
|
112
|
+
"userAgent": "...",
|
|
113
|
+
"timestamp": 1735380000000
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- 交互类(`FID`)
|
|
118
|
+
- `inputDelay = processingStart - startTime`
|
|
119
|
+
- `elementSelector`(触发元素选择器)
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"type": "performance",
|
|
124
|
+
"subType": "first-input",
|
|
125
|
+
"name": "click",
|
|
126
|
+
"startTime": 200.12,
|
|
127
|
+
"duration": 45.67,
|
|
128
|
+
"inputDelay": 18.3,
|
|
129
|
+
"elementSelector": "button#submit.primary",
|
|
130
|
+
"pageUrl": "https://example.com"
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- 事件级交互(`INP`)
|
|
135
|
+
- 采集 `event` entry:`duration`、`inputDelay`、`processingTime`、`presentationDelay`、`interactionId`
|
|
136
|
+
- 默认只记录较慢交互:`durationThreshold: 40ms`
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"type": "performance",
|
|
141
|
+
"subType": "interaction",
|
|
142
|
+
"name": "click",
|
|
143
|
+
"duration": 85.3,
|
|
144
|
+
"startTime": 300.1,
|
|
145
|
+
"processingStart": 315.0,
|
|
146
|
+
"processingEnd": 360.0,
|
|
147
|
+
"inputDelay": 14.9,
|
|
148
|
+
"processingTime": 45.0,
|
|
149
|
+
"presentationDelay": 25.3,
|
|
150
|
+
"interactionId": 123456789,
|
|
151
|
+
"pageUrl": "https://example.com"
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
- 长任务(`LongTask`)
|
|
156
|
+
- `duration`、`startTime`,并尝试提供 `attribution`(来源)
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"type": "performance",
|
|
161
|
+
"subType": "longtask",
|
|
162
|
+
"name": "LongTask",
|
|
163
|
+
"duration": 100.0,
|
|
164
|
+
"attribution": [{ "来源": "longTaskFrame", "类型": "window" }],
|
|
165
|
+
"startTime": 400.5,
|
|
166
|
+
"pageUrl": "https://example.com"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- 资源与网络(`resource`)
|
|
171
|
+
- `dns`、`tcp`、`ttfb`、`transferSize`、`encodedBodySize`、`decodedBodySize`、`nextHopProtocol` 等
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"type": "performance",
|
|
176
|
+
"subType": "resource",
|
|
177
|
+
"sourceType": "fetch",
|
|
178
|
+
"name": "https://api.example.com/data",
|
|
179
|
+
"duration": 120.3,
|
|
180
|
+
"dns": 10.1,
|
|
181
|
+
"tcp": 20.2,
|
|
182
|
+
"ttfb": 50.0,
|
|
183
|
+
"transferSize": 15234,
|
|
184
|
+
"responseBodySize": 14000,
|
|
185
|
+
"responseHeaderSize": 1234,
|
|
186
|
+
"resourceSize": 22000,
|
|
187
|
+
"protocol": "h2",
|
|
188
|
+
"startTime": 500.0,
|
|
189
|
+
"pageUrl": "https://example.com"
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
提示:
|
|
194
|
+
|
|
195
|
+
- 为避免上报循环,SDK 会过滤上报接口本身的请求(`name.includes(reportUrl)`)。
|
|
196
|
+
- 跨域资源如需完整 `ResourceTiming` 细节,请在响应头设置 `Timing-Allow-Origin: *`(或指定来源)。
|
|
197
|
+
|
|
198
|
+
## 路由与 CLS
|
|
199
|
+
|
|
200
|
+
- `CLS` 会在页面隐藏(`visibilitychange`/`pagehide`)或 SPA 路由切换时上报并重置。
|
|
201
|
+
- SDK 内置对 `history.pushState/replaceState` 与 `popstate` 的拦截,用于检测路由变化。
|
|
202
|
+
|
|
203
|
+
## 服务端示例(Node/Express)
|
|
204
|
+
|
|
205
|
+
测试目录已提供完整示例:
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
import express from 'express';
|
|
209
|
+
import cors from 'cors';
|
|
210
|
+
|
|
211
|
+
const app = express();
|
|
212
|
+
app.use(cors());
|
|
213
|
+
app.use(express.json({ type: ['application/json', 'text/plain'] }));
|
|
214
|
+
|
|
215
|
+
app.post('/api/performance', (req, res) => {
|
|
216
|
+
console.log('Received performance data:', JSON.stringify(req.body, null, 2));
|
|
217
|
+
res.status(200).send({ success: true });
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
app.listen(3000, () => {
|
|
221
|
+
console.log('Server running at http://localhost:3000');
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 本地开发与演示
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# 安装依赖
|
|
229
|
+
npm install
|
|
230
|
+
|
|
231
|
+
# 构建产物到 dist/
|
|
232
|
+
npm run build
|
|
233
|
+
|
|
234
|
+
# 启动演示服务器
|
|
235
|
+
node test/server.js
|
|
236
|
+
|
|
237
|
+
# 打开演示页
|
|
238
|
+
open http://localhost:3000/test/index.html
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
测试页包含交互、长任务、网络请求、CLS 触发按钮,便于你观察各类上报。
|
|
242
|
+
|
|
243
|
+
## 兼容性与降级
|
|
244
|
+
|
|
245
|
+
- 依赖 `PerformanceObserver` 的各 EntryType:
|
|
246
|
+
- `paint`(FP/FCP)、`largest-contentful-paint`、`first-input`、`resource`、`longtask`、`layout-shift`、`event`(INP)
|
|
247
|
+
- 若浏览器不支持某类型(例如较旧版本不支持 `event`),对应采集函数会安全地不执行。
|
|
248
|
+
- 上报优先 `navigator.sendBeacon`,不支持时自动降级到 `fetch` 并开启 `keepalive`。
|
|
249
|
+
|
|
250
|
+
## 最佳实践
|
|
251
|
+
|
|
252
|
+
- 生产环境关闭 `log` 避免控制台噪声与性能影响
|
|
253
|
+
- 为跨域资源开启 `Timing-Allow-Origin`
|
|
254
|
+
- 对高频交互可调高阈值(当前 `INP` 使用 40ms)以降低日志量
|
|
255
|
+
- 服务端存储时注意脱敏与隐私合规(SDK 默认不采集 PII)
|