@huyooo/analytics 0.2.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 +86 -0
- package/dist/collectors/pageView.d.ts +3 -0
- package/dist/collectors/performance.d.ts +6 -0
- package/dist/context/browser.d.ts +2 -0
- package/dist/context/device.d.ts +26 -0
- package/dist/context/session.d.ts +2 -0
- package/dist/createAnalyticsClient.d.ts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/navigation/attachHistoryNavigation.d.ts +2 -0
- package/dist/resolveEndpoints.d.ts +3 -0
- package/dist/transport/sendPayload.d.ts +2 -0
- package/dist/types.d.ts +49 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @huyooo/analytics
|
|
2
|
+
|
|
3
|
+
ONES 数据中心配套的前端采集 SDK,用于上报 **页面 PV/UV** 与 **Web Vitals 性能指标**。
|
|
4
|
+
|
|
5
|
+
框架无关,适用于 Vue / React / 原生 SPA。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @huyooo/analytics
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 快速开始
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createAnalyticsClient } from '@huyooo/analytics'
|
|
17
|
+
|
|
18
|
+
const analytics = createAnalyticsClient({
|
|
19
|
+
appId: 'your-app-id',
|
|
20
|
+
logPrefixUrl: 'https://log.example.com/logRestfulApi',
|
|
21
|
+
getToken: () => localStorage.getItem('jwtToken'),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// 监听 pushState / replaceState / popstate / hashchange
|
|
25
|
+
analytics.trackNavigation()
|
|
26
|
+
|
|
27
|
+
// 挂载完成后采集 Web Vitals(LCP、INP、CLS、FCP、TTFB)
|
|
28
|
+
analytics.startPerformance()
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`logPrefixUrl` 会自动推导上报地址:
|
|
32
|
+
|
|
33
|
+
- PV/UV:`{logPrefixUrl}/analytics/add`
|
|
34
|
+
- 性能:`{logPrefixUrl}/performance/add`
|
|
35
|
+
|
|
36
|
+
也可显式指定 `analyticsEndpoint` / `performanceEndpoint` 覆盖。
|
|
37
|
+
|
|
38
|
+
## 配置
|
|
39
|
+
|
|
40
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
41
|
+
|------|------|------|--------|------|
|
|
42
|
+
| `appId` | `string` | 是 | - | 应用 ID,对应 ONES 数据中心租户 |
|
|
43
|
+
| `logPrefixUrl` | `string` | 否 | - | log-server 前缀,用于推导 endpoint |
|
|
44
|
+
| `analyticsEndpoint` | `string` | 否 | `{logPrefixUrl}/analytics/add` | PV/UV 上报地址 |
|
|
45
|
+
| `performanceEndpoint` | `string` | 否 | `{logPrefixUrl}/performance/add` | 性能上报地址 |
|
|
46
|
+
| `getToken` | `() => string \| null \| undefined` | 否 | - | 返回 JWT,关联登录用户 |
|
|
47
|
+
| `enablePerformance` | `boolean` | 否 | `true` | 是否采集 Web Vitals |
|
|
48
|
+
| `dedupePageView` | `boolean` | 否 | `true` | 同一路径重复 PV 去重 |
|
|
49
|
+
| `debug` | `boolean` | 否 | `false` | 开发调试日志(见下方说明) |
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
`createAnalyticsClient(config)` 返回:
|
|
54
|
+
|
|
55
|
+
| 方法 | 说明 |
|
|
56
|
+
|------|------|
|
|
57
|
+
| `trackPageView(options?)` | 手动上报一次 PV,`options.pathname` 可覆盖路径 |
|
|
58
|
+
| `trackNavigation()` | 监听浏览器路由变化并自动上报 PV |
|
|
59
|
+
| `startPerformance()` | 注册 Web Vitals 采集并上报 |
|
|
60
|
+
| `destroy()` | 卸载路由监听,重置内部状态 |
|
|
61
|
+
|
|
62
|
+
`trackNavigation()` 会 patch `history.pushState` / `history.replaceState`,并监听 `popstate`、`hashchange`;首次调用时立即上报当前页 PV。Vue Router、React Router 等基于 History API 的路由均可直接使用。
|
|
63
|
+
|
|
64
|
+
## 上报数据
|
|
65
|
+
|
|
66
|
+
### PV/UV
|
|
67
|
+
|
|
68
|
+
包含 `appId`、设备信息(UA、屏幕、语言等)、位置信息(pathname、referrer、sessionId 等),以及可选的 `authorization`(来自 `getToken`)。
|
|
69
|
+
|
|
70
|
+
### 性能
|
|
71
|
+
|
|
72
|
+
基于 [web-vitals](https://github.com/GoogleChrome/web-vitals),上报 LCP、INP、CLS、FCP、TTFB 及对应阈值配置。
|
|
73
|
+
|
|
74
|
+
## 开发与构建
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm run dev # tsdown watch,未压缩,适合本地调试
|
|
78
|
+
npm run build # 压缩产物(minify + treeshake)
|
|
79
|
+
npm run typecheck
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
发布产物会移除 `console` 调用,`debug: true` 仅在 `npm run dev` 本地调试时有效。
|
|
83
|
+
|
|
84
|
+
## 与 @huyooo/ui 的关系
|
|
85
|
+
|
|
86
|
+
`@huyooo/ui/analytics` 为兼容 re-export,新接入请直接依赖 `@huyooo/analytics`。
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Metric } from 'web-vitals';
|
|
2
|
+
import type { AnalyticsConfig, PerformancePayload } from '../types';
|
|
3
|
+
/** 构建性能上报 payload */
|
|
4
|
+
export declare function buildPerformancePayload(config: AnalyticsConfig, metric: Metric): PerformancePayload;
|
|
5
|
+
/** 注册 Web Vitals 采集(全局只应调用一次) */
|
|
6
|
+
export declare function registerPerformanceCollectors(config: AnalyticsConfig, onMetric: (payload: PerformancePayload) => void): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface AnalyticsDeviceInfo {
|
|
2
|
+
ua: string;
|
|
3
|
+
browser: UAParser.IBrowser;
|
|
4
|
+
cpu: UAParser.ICPU;
|
|
5
|
+
device: UAParser.IDevice;
|
|
6
|
+
engine: UAParser.IEngine;
|
|
7
|
+
os: UAParser.IOS;
|
|
8
|
+
screenResolution: string;
|
|
9
|
+
platform: string;
|
|
10
|
+
language: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AnalyticsLocationInfo {
|
|
13
|
+
host: string;
|
|
14
|
+
hostname: string;
|
|
15
|
+
href: string;
|
|
16
|
+
origin: string;
|
|
17
|
+
pathname: string;
|
|
18
|
+
port: string;
|
|
19
|
+
protocol: string;
|
|
20
|
+
referrer: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
}
|
|
23
|
+
/** 获取设备信息 */
|
|
24
|
+
export declare function getDevice(): AnalyticsDeviceInfo;
|
|
25
|
+
/** 获取页面位置信息 */
|
|
26
|
+
export declare function getLocation(pathname?: string): AnalyticsLocationInfo;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{CLSThresholds as e,FCPThresholds as t,INPThresholds as n,LCPThresholds as r,TTFBThresholds as i,onCLS as a,onFCP as o,onINP as s,onLCP as c,onTTFB as l}from"web-vitals";import{UAParser as u}from"ua-parser-js";import{v4 as d}from"uuid";function f(){return typeof window<`u`&&typeof document<`u`}const p=`_analytics_session_id`;function m(){if(!f())return``;let e=sessionStorage.getItem(p);return e||(e=d(),sessionStorage.setItem(p,e)),e}function h(){return{ua:``,browser:{name:void 0,version:void 0,major:void 0},cpu:{architecture:void 0},device:{model:void 0,type:void 0,vendor:void 0},engine:{name:void 0,version:void 0},os:{name:void 0,version:void 0},screenResolution:``,platform:`Unknown`,language:`Unknown`}}function g(){return{host:``,hostname:``,href:``,origin:``,pathname:``,port:``,protocol:``,referrer:`direct`,sessionId:``}}function _(){return f()?{...new u().getResult(),screenResolution:`${window.screen.width}x${window.screen.height}`,platform:/Android|iOS|iPad|iPhone/i.test(navigator.userAgent)?`Mobile App`:`Web`,language:navigator.language||`Unknown`}:h()}function v(e){if(!f())return g();let t=e??location.pathname;return{host:location.host,hostname:location.hostname,href:`${location.origin}${t}${location.search}${location.hash}`,origin:location.origin,pathname:t,port:location.port,protocol:location.protocol,referrer:document.referrer||`direct`,sessionId:m()}}function y(e){let t=e.getToken?.();return t?t.startsWith(`Bearer `)?t:`Bearer ${t}`:``}function b(a,o){return{appId:a.appId,authorization:y(a),device:_(),location:v(),metric:o,reports:{CLSThresholds:e,FCPThresholds:t,INPThresholds:n,LCPThresholds:r,TTFBThresholds:i}}}function x(e,t){let n=n=>{t(b(e,n))};a(n),o(n),s(n),c(n),l(n)}function S(e){let t=e.getToken?.();if(t)return t.startsWith(`Bearer `)?t:`Bearer ${t}`}function C(e,t){let n={appId:e.appId,device:_(),location:v(t)},r=S(e);return r&&(n.authorization=r),n}function w(e){if(!f())return()=>{};e();let t=history.pushState.bind(history),n=history.replaceState.bind(history);function r(){e()}return history.pushState=(...e)=>{t(...e),r()},history.replaceState=(...e)=>{n(...e),r()},window.addEventListener(`popstate`,r),window.addEventListener(`hashchange`,r),()=>{history.pushState=t,history.replaceState=n,window.removeEventListener(`popstate`,r),window.removeEventListener(`hashchange`,r)}}function T(e){let t=e.logPrefixUrl?.replace(/\/$/,``)??``;return{analytics:e.analyticsEndpoint??`${t}/analytics/add`,performance:e.performanceEndpoint??`${t}/performance/add`}}function E(e,t){let n=JSON.stringify(t);typeof navigator<`u`&&typeof navigator.sendBeacon==`function`&&navigator.sendBeacon(e,new Blob([n],{type:`application/json`}))||D(e,n)}function D(e,t){fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:t,keepalive:!0}).catch(e=>{})}function O(e){let t=T(e),n=!1,r=``,i=null;function a(t,n){e.debug}function o(n){if(!f())return;let i=C(e,n?.pathname),o=i.location.pathname;e.dedupePageView!==!1&&o===r||(r=o,a(`trackPageView`,i),E(t.analytics,i))}function s(){i||(i=w(o),a(`trackNavigation`))}function c(){!f()||n||e.enablePerformance===!1||(n=!0,a(`startPerformance`),x(e,e=>{a(`performance metric`,e.metric),E(t.performance,e)}))}function l(){i?.(),i=null,n=!1,r=``}return{trackPageView:o,trackNavigation:s,startPerformance:c,destroy:l}}export{O as createAnalyticsClient,T as resolveEndpoints};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Metric } from 'web-vitals';
|
|
2
|
+
import type { AnalyticsDeviceInfo, AnalyticsLocationInfo } from './context/device';
|
|
3
|
+
export interface AnalyticsConfig {
|
|
4
|
+
appId: string;
|
|
5
|
+
/** 完整上报地址;未传时由 logPrefixUrl 推导 */
|
|
6
|
+
analyticsEndpoint?: string;
|
|
7
|
+
performanceEndpoint?: string;
|
|
8
|
+
logPrefixUrl?: string;
|
|
9
|
+
/** 返回 JWT,用于关联登录用户 */
|
|
10
|
+
getToken?: () => string | null | undefined;
|
|
11
|
+
/** 是否采集 Web Vitals,默认 true */
|
|
12
|
+
enablePerformance?: boolean;
|
|
13
|
+
/** 同一路径重复 PV 去重,默认 true */
|
|
14
|
+
dedupePageView?: boolean;
|
|
15
|
+
debug?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface AnalyticsClient {
|
|
18
|
+
trackPageView: (options?: {
|
|
19
|
+
pathname?: string;
|
|
20
|
+
}) => void;
|
|
21
|
+
/** 监听 History / hash 路由变化并上报 PV(跨框架) */
|
|
22
|
+
trackNavigation: () => void;
|
|
23
|
+
startPerformance: () => void;
|
|
24
|
+
destroy: () => void;
|
|
25
|
+
}
|
|
26
|
+
export interface ResolvedAnalyticsEndpoints {
|
|
27
|
+
analytics: string;
|
|
28
|
+
performance: string;
|
|
29
|
+
}
|
|
30
|
+
export interface PageViewPayload {
|
|
31
|
+
appId: string;
|
|
32
|
+
device: AnalyticsDeviceInfo;
|
|
33
|
+
location: AnalyticsLocationInfo;
|
|
34
|
+
authorization?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface PerformancePayload {
|
|
37
|
+
appId: string;
|
|
38
|
+
authorization: string;
|
|
39
|
+
device: AnalyticsDeviceInfo;
|
|
40
|
+
location: AnalyticsLocationInfo;
|
|
41
|
+
metric: Metric;
|
|
42
|
+
reports: {
|
|
43
|
+
CLSThresholds: readonly number[];
|
|
44
|
+
FCPThresholds: readonly number[];
|
|
45
|
+
INPThresholds: readonly number[];
|
|
46
|
+
LCPThresholds: readonly number[];
|
|
47
|
+
TTFBThresholds: readonly number[];
|
|
48
|
+
};
|
|
49
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@huyooo/analytics",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "ONES 数据中心配套的前端采集 SDK(流量 PV/UV + Web Vitals 性能)",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://cnb.cool/huyooo/infra/analytics.git"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"dev": "tsdown --watch",
|
|
27
|
+
"build": "npm run clean && npm run build:js && npm run build:types",
|
|
28
|
+
"build:js": "tsdown",
|
|
29
|
+
"build:types": "tsc -b tsconfig.json --emitDeclarationOnly",
|
|
30
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"pub": "npm version patch --force && npm publish --access public",
|
|
33
|
+
"release": "bumpp && npm publish --access public",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"ua-parser-js": "^1.0.38",
|
|
38
|
+
"uuid": "^11.1.0",
|
|
39
|
+
"web-vitals": "^4.2.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^22.5.1",
|
|
43
|
+
"@types/ua-parser-js": "^0.7.39",
|
|
44
|
+
"bumpp": "^10.2.0",
|
|
45
|
+
"tsdown": "^0.21.0",
|
|
46
|
+
"typescript": "^5.5.3"
|
|
47
|
+
}
|
|
48
|
+
}
|