fps-auto-report
v1.5.1
Published
A npm package for FPS monitoring and performance reporting with web-vitals integration
Downloads
34
Maintainers
Readme
fps-auto-report
一个用于监控帧率(FPS)和性能指标并自动上报的 npm 包,集成了 Google 官方的 web-vitals 库。
功能特性
- ✅ FPS 统计:实时监控页面帧率,提供平均、最小、最大 FPS 数据
- ✅ Web Vitals 集成:自动收集 CLS、FCP、LCP、TTFB、INP 等性能指标(基于 web-vitals 5.x)
- ✅ 组件曝光追踪:支持追踪组件出现在视口的次数,避免滚动误报
- 延迟确认机制(默认500ms),确保数据准确性
- 高性能架构:复用 Observer 实例,使用 WeakMap 自动 GC
- 支持多种追踪方式:选择器、DOM元素、自定义ID
- 支持4种上报时机:立即上报、手动上报、批量上报、定时上报
- ✅ 混合上报策略:FPS、Web Vitals 和 Exposure 独立上报,互不耦合
- FPS:支持基于卡顿等级的智能上报或固定间隔上报
- Web Vitals:支持事件驱动上报(指标变化时)或固定间隔上报
- Exposure:支持事件驱动或定时上报
- ✅ 增强的上报层(v1.5.0):提供采样控制、批量传输、离线缓存、失败重试等高级功能
- 采样控制:按页面路径动态采样率配置,减少数据量
- 批量上报:防抖批量上报,减少网络请求
- 离线缓存:localStorage 缓存失败数据,网络恢复后自动上报
- 失败重试:指数退避策略,确保数据可靠传输
- ✅ 性能标记工具(v1.5.0):提供手动埋点功能,追踪业务关键节点性能
- 支持
mark()和measure()方法 - 自动计算耗时并上报
- 支持业务上下文关联(userId、goodsId 等)
- 支持
- ✅ 框架集成(v1.5.0):提供 React Hook 和 Vue Router 集成支持
- React Hook:
useComponentPerf自动追踪组件挂载耗时 - Vue Router:自动追踪路由切换耗时(Vue 2/3 支持)
- React Hook:
- ✅ Babel 插件(v1.5.0):自动为异步函数插入性能追踪代码,构建时自动插桩
- 支持函数名模式匹配(include/exclude)
- 支持多种函数类型:函数声明、函数表达式、箭头函数、类方法
- 追踪代码自动用 try-catch 包裹,避免影响主逻辑
- ✅ 页面信息收集:自动收集 URL、标题、视口大小等页面信息,支持自定义扩展
- ✅ 可配置上报:支持自定义上报接口和上报方式,避免内置上传接口
- ✅ 灵活使用:可作为第三方包在不同项目中使用
- ✅ TypeScript 支持:完整的 TypeScript 类型定义
安装
npm install fps-auto-report web-vitals或
yarn add fps-auto-report web-vitals或
pnpm add fps-auto-report web-vitals使用方法
基础用法
import { createFPSReporter } from 'fps-auto-report';
// 创建上报器实例
const reporter = createFPSReporter({
reportUrl: 'https://your-api.com/report',
reportMethod: 'POST'
});
// 开始监控和上报
reporter.start();完整配置示例
import { createFPSReporter } from 'fps-auto-report';
const reporter = createFPSReporter({
// 必填:上报接口地址(如果使用自定义上报函数则可不填)
reportUrl: 'https://your-api.com/report',
// 可选:上报方法,默认 POST
reportMethod: 'POST', // 'POST' | 'GET' | 'PUT' | 'PATCH'
// 可选:自定义上报函数(优先级高于 reportUrl)
customReporter: async (data) => {
// 自定义上报逻辑
await fetch('https://your-api.com/custom-report', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
},
// 可选:FPS 统计间隔(毫秒),默认 1000
fpsInterval: 1000,
// 可选:是否启用 web-vitals 统计,默认 true
enableWebVitals: true,
// 可选:是否自动上报,默认 true
autoReport: true,
// 可选:上报间隔(毫秒),默认 5000
reportInterval: 5000,
// 可选:是否在页面卸载时上报,默认 true
reportOnUnload: true,
// 可选:自定义页面信息收集函数
collectPageInfo: () => {
return {
url: window.location.href,
title: document.title,
customField: 'custom value',
// 可以添加任意自定义字段
};
},
// 可选:请求头配置
headers: {
'Authorization': 'Bearer token',
'X-Custom-Header': 'value'
},
// 可选:是否启用调试模式,默认 false
debug: true,
// 可选:日志模式,在此模式下所有上报都只打印日志,不进行真实上报
// 适用于测试阶段,避免接口上报出现问题,默认 false
logOnly: false,
// ========== 混合上报策略配置(推荐) ==========
// FPS 上报策略
fpsReportStrategy: {
enabled: true, // 是否启用 FPS 上报,默认 true
levelBased: true, // 是否启用基于等级的智能上报,默认 true
interval: 5000, // 固定上报间隔(当 levelBased 为 false 时使用)
levelThresholds: { // FPS 等级阈值
excellent: 55,
good: 45,
fair: 30,
poor: 20
},
levelStrategy: { // 各等级上报间隔(毫秒)
excellent: 30000, // 优秀:30秒
good: 5000, // 良好:5秒
fair: 5000, // 一般:5秒
poor: 2000, // 较差:2秒
severe: 1000 // 严重:1秒
}
},
// Web Vitals 上报策略
webVitalsReportStrategy: {
enabled: true, // 是否启用 Web Vitals 上报,默认 true
reportOnChange: true, // 指标变化时立即上报(推荐),默认 true
reportOnFirst: true, // 指标首次出现时上报,默认 true
reportInterval: 5000 // 固定上报间隔(当 reportOnChange 为 false 时使用)
}
});
// 开始监控
reporter.start();混合上报策略示例
import { createFPSReporter } from 'fps-auto-report';
const reporter = createFPSReporter({
reportUrl: 'https://your-api.com/report',
// FPS 按等级智能上报
fpsReportStrategy: {
enabled: true,
levelBased: true,
levelThresholds: { excellent: 55, good: 45, fair: 30, poor: 20 },
levelStrategy: {
excellent: 30000, // 优秀时降低上报频率
good: 5000,
fair: 5000,
poor: 2000, // 较差时提高上报频率
severe: 1000 // 严重时高频上报
}
},
// Web Vitals 事件驱动上报
webVitalsReportStrategy: {
enabled: true,
reportOnChange: true, // 指标变化时立即上报
reportOnFirst: true // 首次出现时上报
}
});
reporter.start();手动上报
// 上报所有数据(FPS + Web Vitals)
await reporter.report();
// 或
await reporter.reportAll();
// 仅上报 FPS 数据
await reporter.reportFPS();
// 仅上报 Web Vitals 数据
await reporter.reportWebVitals();
// 仅上报曝光数据
await reporter.reportExposure('element-id'); // 上报特定元素
await reporter.reportExposure(); // 上报所有元素
// 获取当前 FPS 数据
const fpsData = reporter.getFPSData();
console.log('Current FPS:', fpsData.fps);
console.log('FPS Level:', fpsData.level);
console.log('Average FPS:', fpsData.averageFPS);
// 获取 web-vitals 指标
const metrics = reporter.getWebVitalsMetrics();
console.log('Web Vitals:', metrics);
// 获取曝光追踪器
const exposureTracker = reporter.getExposureTracker();
// 追踪元素
const elementId = exposureTracker.track('#my-component', 'component-1');
// 获取曝光数据
const exposureData = exposureTracker.getExposureData('component-1');
console.log('Exposure count:', exposureData?.exposureCount);
// 重置统计数据
reporter.reset();
// 停止监控
reporter.stop();使用类方式
import FPSReporter from 'fps-auto-report';
const reporter = new FPSReporter({
reportUrl: 'https://your-api.com/report'
});
reporter.start();组件曝光追踪示例
import { createFPSReporter } from 'fps-auto-report';
const reporter = createFPSReporter({
reportUrl: 'https://your-api.com/report'
});
// 获取曝光追踪器
const tracker = reporter.getExposureTracker();
// 方式1: 通过选择器追踪
tracker.track('#ad-banner', 'ad-1');
// 方式2: 通过 DOM 元素追踪
const element = document.querySelector('.product-card');
if (element) {
tracker.track(element, 'product-1');
}
// 开始监控
reporter.start();
// 立即上报(事件驱动)
import { ExposureTracker } from 'fps-auto-report';
const immediateTracker = new ExposureTracker({
reportOnExposure: true,
onExposure: async (event) => {
await fetch('/api/exposure', {
method: 'POST',
body: JSON.stringify(event)
});
}
});
// 手动上报
await reporter.reportExposure('ad-1'); // 上报特定元素
await reporter.reportExposure(); // 上报所有元素
// 批量上报(与其他数据一起)
await reporter.reportAll(); // 包含 FPS + Web Vitals + Exposure
// 定时上报
setInterval(async () => {
await reporter.reportExposure();
}, 30000); // 每 30 秒上报一次更多曝光追踪功能的使用方法,请参考 组件曝光监控使用指南。
日志模式(测试阶段)
在测试阶段,可以使用日志模式来避免接口上报出现问题。在此模式下,所有上报都只打印日志,不进行真实的上报。
import { createFPSReporter } from 'fps-auto-report';
const reporter = createFPSReporter({
reportUrl: 'https://your-api.com/report',
// 启用日志模式(测试阶段)
logOnly: true, // 所有上报都只打印日志,不进行真实上报
debug: true // 建议同时启用调试模式,查看详细日志
});
reporter.start();日志模式输出示例:
[FPS Reporter] [LOG ONLY MODE] Would report data: {
"fps": { ... },
"pageInfo": { ... },
"timestamp": 1234567890
}
[FPS Reporter] [LOG ONLY MODE] Report URL: https://your-api.com/report
[FPS Reporter] [LOG ONLY MODE] Report Method: POST增强的上报层(批量上报、采样控制、离线缓存)
v1.5.0 新增的增强上报功能,提供更可靠和高效的数据上报机制。
import { createFPSReporter } from 'fps-auto-report';
const reporter = createFPSReporter({
reportUrl: 'https://your-api.com/report',
// 启用批量上报模式
useBatchReport: true,
// MetricReporter 配置
metricReporterConfig: {
// 采样控制:按页面路径配置采样率
sampleRateMap: {
'/': 1, // 首页100%采样
'/goods/detail': 0.8, // 商品详情页80%采样
'/cart': 0.5, // 购物车50%采样
default: 0.3 // 其他页面30%采样
},
// 批量上报配置
maxQueueSize: 50, // 最大队列大小
batchDebounceDelay: 500, // 防抖延迟(毫秒)
// 离线缓存配置
enableOfflineCache: true, // 启用离线缓存
maxCacheSize: 100, // 最大缓存条数
// 失败重试配置
enableRetry: true, // 启用重试
retryConfig: {
maxCount: 3, // 最大重试次数
initialDelay: 1000, // 初始延迟(毫秒)
exponentialBackoff: true // 指数退避
}
}
});
reporter.start();📖 详细文档
性能标记工具(手动埋点)
v1.5.0 新增的手动埋点功能,用于追踪业务关键节点性能。
import { mark, measure } from 'fps-auto-report';
// 标记开始
const startMark = mark('checkout:start', {
userId: '123',
orderId: '456'
});
// ... 执行业务逻辑
// 标记结束并计算耗时
const endMark = mark('checkout:end', {
userId: '123',
orderId: '456'
});
// 计算耗时(自动上报)
const duration = measure(
'checkout:duration',
startMark,
endMark,
{ userId: '123', orderId: '456' }
);
console.log(`结账耗时: ${duration}ms`);📖 详细文档
React Hook 集成
v1.5.0 新增的 React Hook,自动追踪组件挂载耗时。
import { useComponentPerf } from 'fps-auto-report';
// 自动追踪组件挂载耗时
const MyComponent = () => {
useComponentPerf('MyComponent', {
userId: '123',
pageType: 'product'
});
return <div>...</div>;
};
// 手动控制渲染耗时追踪
import { useManualComponentPerf } from 'fps-auto-report';
const MyComponent = () => {
const { start, end } = useManualComponentPerf('MyComponent');
const handleClick = () => {
start();
// ... 执行操作
end('click:duration');
};
return <button onClick={handleClick}>Click</button>;
};📖 详细文档
Vue Router 集成
v1.5.0 新增的 Vue Router 集成,自动追踪路由切换耗时。
// Vue 3
import { createRouter } from 'vue-router';
import { setupVueRouterPerf } from 'fps-auto-report';
const router = createRouter({ /* ... */ });
setupVueRouterPerf(router, {
routeDelay: 300, // 等待DOM更新的延迟时间
debug: true
});
// Vue 2
import VueRouter from 'vue-router';
import { setupVue2RouterPerf } from 'fps-auto-report';
const router = new VueRouter({ /* ... */ });
setupVue2RouterPerf(router);📖 详细文档
Babel 插件(自动插桩)
使用 Babel 插件自动为异步函数插入性能追踪代码,无需手动埋点。
📖 详细文档
# 安装插件
npm install --save-dev babel-plugin-fps-auto-report// babel.config.js
module.exports = {
plugins: [
[
'babel-plugin-fps-auto-report',
{
trackerName: 'PerfTracker',
include: 'fetch|load|submit|get|post'
}
]
]
};插桩前:
async function fetchUserData(userId) {
const response = await fetch(`/api/user/${userId}`);
return response.json();
}插桩后(自动):
async function fetchUserData(userId) {
try {
PerfTracker.mark('fetchUserData:exec:start');
} catch (_e) {}
const response = await fetch(`/api/user/${userId}`);
try {
PerfTracker.mark('fetchUserData:exec:end');
PerfTracker.measure('fetchUserData:exec:duration', 'fetchUserData:exec:start', 'fetchUserData:exec:end');
} catch (_e) {}
return response.json();
}📖 Babel 插件详细文档 | 测试报告
配置选项:
{
trackerName: 'PerfTracker', // 追踪器名称
include: 'fetch|load|submit', // 函数名匹配模式(正则)
exclude: '^_|internal', // 排除的函数名模式
markPrefix: 'api:', // 标记前缀
measurePrefix: 'api:', // 指标前缀
autoMeasure: true, // 是否自动测量
wrapInTryCatch: true // 是否用 try-catch 包裹(默认 true)
}配置选项
FPSReporterConfig
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| reportUrl | string | 否* | - | 上报接口地址(如果使用 customReporter 则可不填) |
| reportMethod | 'POST' \| 'GET' \| 'PUT' \| 'PATCH' | 否 | 'POST' | 上报方法 |
| customReporter | (data: ReportData) => void \| Promise<void> | 否 | - | 自定义上报函数 |
| fpsInterval | number | 否 | 1000 | FPS 统计间隔(毫秒) |
| enableWebVitals | boolean | 否 | true | 是否启用 web-vitals 统计 |
| autoReport | boolean | 否 | true | 是否自动上报 |
| reportInterval | number | 否 | 5000 | 上报间隔(毫秒) |
| reportOnUnload | boolean | 否 | true | 是否在页面卸载时上报 |
| collectPageInfo | () => PageInfo \| Promise<PageInfo> | 否 | 默认收集函数 | 自定义页面信息收集函数 |
| headers | Record<string, string> | 否 | {} | 请求头配置 |
| debug | boolean | 否 | false | 是否启用调试模式 |
| logOnly | boolean | 否 | false | 日志模式:在此模式下所有上报都只打印日志,不进行真实上报 |
| fpsReportStrategy | FPSReportStrategy | 否 | 见下方 | FPS 上报策略配置 |
| webVitalsReportStrategy | WebVitalsReportStrategy | 否 | 见下方 | Web Vitals 上报策略配置 |
| useBatchReport | boolean | 否 | false | 是否启用批量上报模式(v1.5.0) |
| metricReporterConfig | MetricReporterConfig | 否 | - | MetricReporter 配置(v1.5.0) |
FPSReportStrategy
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| enabled | boolean | true | 是否启用 FPS 上报 |
| levelBased | boolean | true | 是否启用基于等级的智能上报 |
| interval | number | 5000 | 固定上报间隔(毫秒,当 levelBased 为 false 时使用) |
| levelThresholds | FPSLevelThresholds | 见下方 | FPS 等级阈值配置 |
| levelStrategy | FPSLevelReportStrategy | 见下方 | FPS 等级上报策略配置 |
WebVitalsReportStrategy
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| enabled | boolean | true | 是否启用 Web Vitals 上报 |
| reportOnChange | boolean | true | 指标变化时立即上报(推荐) |
| reportOnFirst | boolean | true | 指标首次出现时上报 |
| reportInterval | number | 5000 | 固定上报间隔(毫秒,当 reportOnChange 为 false 时使用) |
数据类型
ReportData
上报的数据结构:
interface ReportData {
fps?: FPSData; // FPS 统计数据
webVitals?: Metric[]; // web-vitals 指标数组
exposure?: ExposureEvent | ExposureEvent[]; // 曝光数据(单个或多个)
pageInfo: PageInfo; // 页面信息
timestamp: number; // 时间戳
}FPSData
FPS 统计数据:
interface FPSData {
fps: number; // 当前 FPS
averageFPS: number; // 平均 FPS
minFPS: number; // 最小 FPS
maxFPS: number; // 最大 FPS
frameCount: number; // 帧数
timestamp: number; // 时间戳
}PageInfo
页面信息(可扩展):
interface PageInfo {
url: string; // 页面 URL
title?: string; // 页面标题
referrer?: string; // 来源页面
userAgent?: string; // 用户代理
viewport?: { // 视口大小
width: number;
height: number;
};
timestamp?: number; // 时间戳
[key: string]: any; // 自定义字段
}ExposureEvent
曝光事件数据:
interface ExposureEvent {
elementId: string; // 元素标识
exposureCount: number; // 曝光次数
firstExposureTime: number; // 首次曝光时间
lastExposureTime: number; // 最后曝光时间
exposureRecords: Array<{ // 曝光记录列表
timestamp: number; // 曝光时间戳
duration?: number; // 曝光持续时间(毫秒)
}>;
elementInfo?: { // 元素信息
tagName?: string;
className?: string;
id?: string;
textContent?: string;
};
}上报策略说明
混合策略设计
本库采用混合上报策略,FPS、Web Vitals 和 Exposure 独立上报,互不耦合:
FPS 上报:
- 基于卡顿等级的智能上报(推荐):根据 FPS 值自动划分等级,不同等级采用不同上报频率
- 固定间隔上报:按固定时间间隔上报
Web Vitals 上报:
- 事件驱动上报(推荐):指标变化或首次出现时立即上报,符合 Web Vitals 的特性
- 固定间隔上报:按固定时间间隔上报
Exposure 上报:
- 立即上报(事件驱动):曝光确认后立即上报
- 手动上报:开发者主动调用
- 批量上报:与其他性能数据一起上报
- 定时上报:按固定时间间隔上报
为什么需要混合策略?
- FPS 是持续变化的实时指标,适合按等级动态调整上报频率
- Web Vitals 指标通常在特定时机出现(如页面加载、用户交互),适合事件驱动上报
- Exposure 是用户行为触发的指标,适合事件驱动或定时上报
- 三者独立上报,避免相互影响,更符合各自的数据特性
注意事项
- 依赖要求:需要安装
web-vitals作为 peer dependency- React Hook 需要安装
react(peer dependency) - Vue Router 集成需要安装
vue-router(peer dependency)
- React Hook 需要安装
- 浏览器兼容性:
- 需要支持
requestAnimationFrame和performance.now()的现代浏览器 - 曝光追踪功能需要支持
IntersectionObserverAPI(IE 不支持) - 批量上报功能需要支持
localStorageAPI
- 需要支持
- 上报接口:确保你的上报接口能够处理 JSON 格式的数据
- 页面卸载上报:使用
sendBeaconAPI 确保页面卸载时数据能够可靠上报 - 向后兼容:旧版配置(
enableLevelBasedReport、fpsLevelThresholds等)仍然支持,但推荐使用新的策略配置 - 曝光追踪性能:已优化支持追踪大量元素(1000+),使用 Observer 复用和 WeakMap 自动 GC
- v1.5.0 新功能:
- 日志模式:
logOnly配置项,测试阶段只打印日志,不进行真实上报 - 批量上报模式:启用后会自动使用
MetricReporter进行批量上报 - 采样控制:通过
sampleRateMap配置不同页面的采样率 - 离线缓存:自动缓存失败的上报数据,网络恢复后自动重试
- 性能标记:使用
mark()和measure()进行手动埋点 - Babel 插件:构建时自动插桩,无需手动埋点
- 日志模式:
开发
# 安装依赖
npm install
# 构建
npm run build
# 开发模式(监听文件变化)
npm run devLicense
MIT
