# @evumi/tracker 中文文档

规范地址：https://npmcn.com/package/%40evumi/tracker/

版本：0\.2\.34
npm 元数据更新时间：2026-11-12T05:06:10.497Z
中文译文更新时间：2026-11-14T02:45:48.593Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40evumi/tracker
原文对照：https://npmcn.com/package/%40evumi/tracker/?lang=original
项目主页：https://github.com/evumi/evumi#readme
源码仓库：https://github.com/evumi/evumi

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：66.4 kB，27 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：vue ^3\.5\.0，next \>=14 \<17，react \>=18 \<20，vue-router ^4\.0\.0 \|\| ^5\.0\.0，@tanstack/react-router ^1\.170\.41
- 首次发布：2026-10-16T06:04:55.645Z
- 最新版本发布：2026-11-12T05:06:10.302Z
- 近 30 天下载量：7927（2026-10-14 至 2026-11-12，npm 官方下载统计）
- 已发布版本数：47（近 12 个月 47 个）

## 中文简介

与共享路由模板和框架适配器兼容的可扩展分析

## 安装

```sh
npm install @evumi/tracker
```

也可以使用：`pnpm add @evumi/tracker`、`yarn add @evumi/tracker`、`bun add @evumi/tracker`

## README

# @evumi/tracker

[English](https://npmcn.com/package/%40evumi/tracker/README.md) · **简体中文**

从公共 npm 安装，无需令牌：

```sh
npm install @evumi/tracker
# pnpm add @evumi/tracker
# yarn add @evumi/tracker
# bun add @evumi/tracker
```

React / Next.js / TanStack / Vue / Electron 共用此包的不同入口。原有私有 GitHub Packages 镜像继续发布；使用 npm 时删除 `.npmrc` 中旧的 `@evumi:registry=https://npm.pkg.github.com`，或仅将该 scope 改为 `https://registry.npmjs.org`，保留其他配置。可用 `@evumi/tracker@<version>` 固定版本；站点设置仍提供当前实例 `.tgz` 下载作为备用。

`domain` 是在 Evumi 中创建的被统计站点，`apiHost` 是你的 Evumi 实例 origin（如 `https://stats.example.com`，也支持端口）。SDK 自动追加 `/api/event`，不要在 `apiHost` 中填路径、查询参数或凭据。所有框架和 Electron 共用此配置，支持自部署。生产使用 HTTPS，并在 CSP `connect-src` 允许该地址；浏览器代码不需要 npm 或 Evumi 管理密钥。

沿用校验过的 Plausible v3.2.1 MIT tracker；路由适配器处理模板和重复导航。tracker 打包进引入 SDK 的模块，首个事件前不再额外加载 chunk。SDK 不占用 `window.plausible`，可与 Plausible 官方脚本或 npm SDK 共存；仅当页面已有向同一 Evumi 服务器上报的脚本标签时拒绝启动，避免重复计数。

## Electron（渲染进程）

```ts
// src/analytics.ts，在 renderer 中使用；不要在 main 或 preload 发送。
import { createElectronTracker } from '@evumi/tracker/electron'
export const analytics = createElectronTracker({
  domain: 'desktop.example.com', // 先在 Evumi 创建这个站点
  apiHost: 'https://stats.example.com',
  routePatterns: ['/projects/:id'],
})
```

普通 Hash 路由：

```ts
import { installElectronHashRouter } from '@evumi/tracker/electron'
import { analytics } from './analytics'
const stop = installElectronHashRouter(analytics)
window.addEventListener('beforeunload', stop, { once: true })

// 业务成功回调，不在初始化时调用
export function onProjectCreated() {
  void analytics.track('Project created', { props: { plan: 'pro' } })
}
```

React / TanStack / Vue 桌面应用将这个 `analytics` 传入对应框架适配器即可，不再同时安装 Hash 监听。手动导航使用 `analytics.pageview({ url: '/projects/123' })`。无 Router 的不同窗口可传各自的应用路径，例如 `/settings`。每个渲染窗口独立初始化，统计仍按服务器的匿名会话规则归并，默认不新增永久设备 ID。

| 渲染 URL | 上报 URL（配置上述模板） |
| --- | --- |
| `file:///Users/alice/app/index.html` | `https://desktop.example.com/` |
| `file:///…/index.html#/projects/123` | `https://desktop.example.com/projects/:id` |
| `app://renderer/projects/123` | `https://desktop.example.com/projects/:id` |
| `http://localhost:5173/#/projects/123` | `https://desktop.example.com/projects/:id` |

默认解析 `#/` 和 `#!/`，可用 `hashRouting: false` 关闭。不自动发送文件路径、文件 URL 的查询参数和 referrer；路由中的 query 继续使用公共白名单规则。显式传入的属性、URL 和事件名由接入方选择，勿传文件目录或用户身份数据。Electron 入口允许本地 renderer 发送，开发环境同样会计数，可按环境决定是否挂载。自动外链/文件下载/表单捕获关闭；使用明确的业务事件记录桌面操作。主进程直接调用会返回 `skipped`，没有实现主进程 Node SDK 或离线持久队列。

无需 Electron 依赖或 preload/IPC 桥；保留 `contextIsolation: true`、`nodeIntegration: false`、`sandbox: true` 和默认 `webSecurity`，在已有 CSP `connect-src` 中添加 Evumi 的 HTTPS origin。普通 `file://` 的跨域请求使用 `/api/event` 的公开 CORS，不需要关闭安全设置。参见 [Electron 安全指南](https://www.electronjs.org/docs/latest/tutorial/security) 和 [上下文隔离](https://www.electronjs.org/docs/latest/tutorial/context-isolation)。

## 公共配置

```ts
import { createTracker } from '@evumi/tracker'

export const analytics = createTracker({
  domain: 'example.com',
  apiHost: 'https://stats.example.com',
  routePatterns: ['/users/new', '/users/:id', '/products/:id/reviews'],
  outboundLinks: true,
  fileDownloads: true,
})

await analytics.pageview({ routeTemplate: '/users/:id' })
await analytics.track('Signup', { props: { plan: 'pro' } })
await analytics.track('Purchase', { revenue: { amount: 29, currency: 'USD' } })
```

`/users/123`、`/users/456` 会归到 `/users/:id`，但两次实际导航仍产生两次 pageview；静态规则 `/users/new` 优先于动态规则。未命中显式规则的路径原样上报，不通过数字或 UUID 猜测路由。支持 `:id`、Next `[id]`/`[...slug]`/`[[...slug]]`、TanStack `$id`/`$`/`{-$id}`、Vue `:pathMatch(.*)*`；报表统一使用 `:name`。不支持的复杂路由正则会报错，应提供简单模板。

默认只保留 UTM、`ref` 和 `source` 参数，不发送 hash；其他参数需要 `includeSearchParams: ['sort']` 显式允许。浏览器默认不统计 localhost，开发验证需要 `captureOnLocalhost: true`。沿用 Plausible `localStorage.plausible_ignore` 排除行为，默认不创建持久访客 ID 或 Cookie。

`pageview` 和 `track` 返回 `{ status: 'sent' | 'skipped' | 'error' }`。`sent` 表示接收端返回成功 HTTP 状态，不代表统计已入库。可通过 `onError` 接错误；框架适配器不会把网络失败抛到页面。SSR 调用为 `skipped`，不访问浏览器对象。

## React

```tsx
import { EvumiProvider, EvumiPageview, useEvumi } from '@evumi/tracker/react'
import { analytics } from './analytics'

// 接收你实际使用的路由器状态；不另行 patch History API。
function App({ pathname, search }: { pathname: string; search: string }) {
  return <EvumiProvider tracker={analytics}>
    <EvumiPageview url={pathname + search} />
    <YourRoutes />
  </EvumiProvider>
}
// 后代组件内：const analytics = useEvumi(); analytics.track('Signup')
```

pageview 与 Plausible 的 SPA 规则一致：仅在 pathname 变化时发送，因此仅 query/hash 变化、重复通知及 React StrictMode effect 重放会合并，真实的 A→B→A 导航和连续两次自定义事件保留。props 变化本身不触发重复 pageview。`navigationId` 已弃用并被忽略。与 Plausible 相同，隐藏或预渲染页面的首个 pageview 会等到页面可见再发送，从往返缓存（bfcache）恢复的页面会再次发送 pageview。

## Next.js App Router

```tsx
// app/analytics.tsx
'use client'
import { createTracker } from '@evumi/tracker'
import { EvumiNext } from '@evumi/tracker/nextjs'
const tracker = createTracker({
  domain: 'example.com', apiHost: 'https://stats.example.com',
  routePatterns: ['/products/[id]', '/users/[id]'],
})
export default function Analytics() { return <EvumiNext tracker={tracker} /> }
// 在 app/layout.tsx 的 body 内只挂载一次 <Analytics />
```

App Router 的 `usePathname()` 只返回真实路径，不提供文件路由模板，因此需显式配置 `routePatterns` 或给 `EvumiNext` 传 `routeTemplate`。组件内置 Suspense 边界；重写路径同样由你显式映射。

## Next.js Pages Router

```tsx
// pages/_app.tsx
import { EvumiNextPages } from '@evumi/tracker/nextjs/pages'
import { analytics } from '../analytics'
export default function App({ Component, pageProps }) {
  return <><EvumiNextPages tracker={analytics} /><Component {...pageProps} /></>
}
```

读取 `router.pathname`（如 `/products/[id]`），等待 `isReady` 后上报。App/Pages 两个适配器按实际路由架构选用，不在同一页面重复挂载。

## TanStack Router / Start

```tsx
import { EvumiTanStack } from '@evumi/tracker/tanstack'
import { Outlet } from '@tanstack/react-router'
import { analytics } from './analytics'
// 放在 root route 组件内，位于 RouterProvider 下。
export function Root() { return <><EvumiTanStack tracker={analytics} /><Outlet /></> }
```

导航成功且匹配完成后，读取最深层 match 的 `fullPath`，把 `/users/$id` 转为 `/users/:id`；不统计预加载、pending 或失败的导航。

## Vue 3 / Vue Router

```ts
import { createEvumiPlugin } from '@evumi/tracker/vue'
import { analytics } from './analytics'
app.use(router)
app.use(createEvumiPlugin({ tracker: analytics, router }))
app.mount('#app')
```

导航成功后读取最深层匹配记录的 `path`，初始路由就绪后补发首次浏览；取消/失败导航不统计。组件内 `useEvumi()` 可发送事件。也可以手动调用 `installVueRouter(analytics, router)`，返回取消订阅函数。应用卸载会移除路由监听；上游 engagement 监听器按页面生命周期保留。

## 包边界和参考

只导入 core 不会引入 React、Vue 或 Next。框架是可选 peer dependency；浏览器 runtime 按需动态加载，并复用每页单例，多个框架入口不会重复注册 tracker。不同配置在同页初始化会返回错误。

-   [Next.js usePathname](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
-   [TanStack RouteMatch](https://tanstack.com/router/latest/docs/framework/react/api/router/RouteMatchType)
-   [Vue Router afterEach](https://router.vuejs.org/guide/advanced/navigation-guards.html#Global-After-Hooks)

## 可选浏览器匿名 ID

默认保持 Plausible 无 Cookie 模式。需要跨标签页、刷新和日期保持同一匿名访客时，在站点基本设置开启「浏览器匿名 ID」，并在共享 SDK 配置中添加 `identity: 'browser'`。所有框架和 Electron 入口共用该实现。

SDK 通过 IndexedDB 事务按当前 origin 与站点创建 UUID，避免多个标签页同时首次打开各自产生 ID。服务端按站点再次哈希，原始 ID 不进入队列和 DuckDB。存储不可用时回退默认模式；清理站点数据、切浏览器配置或设备会产生新 ID。同一浏览器配置多人共用无法识别人，未实现跨域 linker 或账号 identify。原版 Plausible JS 保持无 Cookie 模式。客户端收入需在站点设置允许后才接收。

## Transient delivery failures

The SDK retries network errors, timeouts, 408, 429 and 5xx for up to five minutes. It keeps at most 64 events / 256 KB in first-party sessionStorage, falling back to memory when storage is unavailable. Per-event IDs prevent retry duplicates on the matching Evumi collector. Upgrade collector and analytics before SDK consumers. Closing the tab, clearing storage or exceeding limits can still lose events. See [delivery guarantees](https://npmcn.com/package/docs/delivery-retries.md).

## 常见问题

### @evumi/tracker 是什么？

与共享路由模板和框架适配器兼容的可扩展分析

### 如何安装 @evumi/tracker？

在项目目录运行 npm install @evumi/tracker，或使用 pnpm add / yarn add / bun add。

### @evumi/tracker 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @evumi/tracker 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @evumi/tracker 可以商用吗？

@evumi/tracker 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @evumi/tracker 的下载量有多少？

根据 npm 官方下载统计，@evumi/tracker 在 2026/10/14 – 2026/11/12 这 30 天内被下载 7,927 次，日均约 264 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @evumi/tracker 还在维护吗？

最新版本 0\.2\.34 发布于 2026/11/12（1 天前）；至今共发布 47 个版本，其中过去 12 个月发布了 47 个；首次发布于 2026/10/16。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

