Files
TrueGrowth/specs/005-declarative-tracking/quickstart.md

10 KiB

Quick Start: 声明式埋点上报系统

Feature: 005-declarative-tracking Audience: 开发者 Time: 5-10 分钟

Overview

本指南帮助您快速上手使用声明式埋点系统,从基础的手动埋点到高级的自动埋点功能。


Prerequisites

  • Node.js 18+
  • 项目已集成 Umami Analytics
  • 了解基本的 React 和 TypeScript

Installation

1. 确认 Umami 已配置

检查 apps/web/index.html 或应用入口是否有 Umami 脚本:

<!-- 应该已存在 -->
<script
  defer
  src="https://your-umami-domain/script.js"
  data-website-id="your-website-id"
></script>

2. 安装依赖

# 项目依赖已包含,无需额外安装
npm install

Basic Usage (基础埋点)

Step 1: 在 Drawnix 中启用埋点插件

修改 packages/drawnix/src/drawnix.tsx:

import { withTracking } from './plugins/tracking';

// 在其他插件后添加 withTracking
const editor = withMind(
  withDraw(
    withFreehand(
      withTracking(
        // 其他插件...
      )
    )
  )
);

Step 2: 添加手动埋点属性

在任意 React 组件中使用 track 属性:

// 示例: UnifiedToolbar.tsx
export const UnifiedToolbar = () => {
  return (
    <div className="toolbar">
      {/* 基础埋点 */}
      <Button track="toolbar_click_pen">
        <PenIcon />
      </Button>

      {/* 带参数的埋点 */}
      <Button
        track="toolbar_click_shape"
        track-params='{"shape": "rectangle"}'
      >
        <RectIcon />
      </Button>

      {/* 不埋点 */}
      <Button>
        Normal Button
      </Button>
    </div>
  );
};

Step 3: 验证埋点

  1. 启动开发服务器: npm start
  2. 打开浏览器控制台(F12)
  3. 点击添加了 track 属性的按钮
  4. 查看控制台日志(开发模式下会输出):
    [Tracking] Event tracked: toolbar_click_pen
    [Tracking] Batching event (1/10)
    
  5. 等待 5 秒或点击 10 个事件后,检查网络请求:
    POST https://your-umami-domain/api/send
    Payload: { name: "toolbar_click_pen", data: { version: "1.2.3", url: "..." } }
    

Advanced Usage (高级功能)

1. 自动埋点模式

启用自动埋点,无需手动添加 track 属性:

// packages/drawnix/src/drawnix.tsx
const editor = withTracking(
  // ... other plugins
  {
    autoTrack: true  // 启用自动埋点
  }
);

效果:

  • 所有 <button>, <a>, <input type="button"> 等交互元素自动埋点
  • 事件名自动生成,基于元素特征(如按钮文本、ID、aria-label)
  • 排除导航栏、页脚、工具栏等区域

示例:

// 无需 track 属性
<Button id="save-btn">保存</Button>

// 自动生成事件名: auto_click_save-btn 或 auto_click_保存

2. 排除特定元素

使用 data-track-ignore 属性排除埋点:

<nav data-track-ignore>
  <Button>导航按钮</Button>  {/* 不会自动埋点 */}
</nav>

<Button data-track-ignore>
  临时不埋点的按钮
</Button>

3. 支持其他事件类型

除了 click,还支持 hover、focus 等事件:

// Hover 埋点
<Card track-hover="card_hover_features">
  Feature Card
</Card>

// Focus 埋点
<Input track-focus="input_focus_search" />

// 同时支持多种事件
<Element
  track="element_click"
  track-hover="element_hover"
  track-focus="element_focus"
/>

Configuration (配置)

全局配置

创建 packages/drawnix/src/config/tracking.config.ts:

import type { TrackConfig } from '../types/tracking.types';

export const trackingConfig: Partial<TrackConfig> = {
  autoTrack: false,           // 默认关闭自动埋点
  debounceTime: 500,          // 防抖 500ms
  logLevel: 'error',          // 生产环境只记录错误
  batchConfig: {
    enabled: true,
    batchSize: 10,            // 10 个事件批量上报
    batchTimeout: 5000        // 或 5 秒超时
  },
  excludedSelectors: [
    'nav',
    'header',
    'footer',
    '[data-track-ignore]',
    '.no-track'               // 自定义排除类
  ]
};

应用配置:

// drawnix.tsx
import { trackingConfig } from './config/tracking.config';

const editor = withTracking(
  // ... plugins
  trackingConfig
);

环境变量配置

vite.config.ts 中注入版本号:

// vite.config.ts
import { defineConfig } from 'vite';
import packageJson from './package.json';

export default defineConfig({
  define: {
    'import.meta.env.VITE_APP_VERSION': JSON.stringify(packageJson.version)
  }
});

Testing (测试)

开发环境测试

启用调试模式:

const editor = withTracking(
  // ... plugins
  {
    devMode: true,          // 启用开发模式
    logLevel: 'debug'       // 输出详细日志
  }
);

控制台输出示例:

[Tracking] Service initialized
[Tracking] Event captured: button_click_save
[Tracking] Debounce check passed
[Tracking] Event queued (1/10)
[Tracking] Batch timeout started (5s)
[Tracking] Batch uploading (10 events)
[Tracking] Upload successful

单元测试

// packages/drawnix/src/services/tracking/__tests__/tracking-service.test.ts
import { TrackingService } from '../tracking-service';

describe('TrackingService', () => {
  let service: TrackingService;

  beforeEach(() => {
    service = new TrackingService(mockConfig);
  });

  it('should track event', async () => {
    await service.track('test_event', { param: 'value' });

    expect(service.getStats().totalEvents).toBe(1);
  });

  it('should debounce duplicate events', async () => {
    const element = document.createElement('button');

    await service.track('test_event', {}, element);
    await service.track('test_event', {}, element);  // 应被防抖

    expect(service.getStats().totalEvents).toBe(1);
  });
});

E2E 测试

// tests/e2e/tracking/declarative-tracking.spec.ts
import { test, expect } from '@playwright/test';

test('should track button click', async ({ page }) => {
  // 监听网络请求
  const requests: any[] = [];
  page.on('request', request => {
    if (request.url().includes('/api/send')) {
      requests.push(request.postDataJSON());
    }
  });

  // 访问页面
  await page.goto('http://localhost:7200');

  // 点击埋点按钮
  await page.click('[track="button_click_save"]');

  // 等待批量上报(最多 5 秒)
  await page.waitForTimeout(5500);

  // 验证请求
  expect(requests.length).toBeGreaterThan(0);
  expect(requests[0].name).toBe('button_click_save');
  expect(requests[0].data.version).toBeDefined();
  expect(requests[0].data.url).toContain('localhost:7200');
});

Troubleshooting (问题排查)

1. 埋点不生效

症状: 点击元素后没有上报事件

排查步骤:

  1. 检查 Umami SDK 是否加载:
    console.log(window.umami); // 应该是一个对象
    
  2. 检查插件是否启用:
    // drawnix.tsx 中是否调用了 withTracking
    
  3. 检查元素是否被排除:
    // 元素是否在 nav/header/footer 内?
    // 元素是否有 data-track-ignore 属性?
    
  4. 检查防抖:
    // 是否在 500ms 内重复点击?
    

2. 批量上报不触发

症状: 事件队列一直累积,不上报

排查步骤:

  1. 检查批量配置:
    batchConfig: {
      enabled: true  // 是否启用?
    }
    
  2. 检查网络连接:
    curl https://your-umami-domain/api/send
    
  3. 查看控制台错误:
    // 是否有 CORS 错误?
    // 是否有 401/403 认证错误?
    

3. 缓存不工作

症状: 离线时事件丢失,未缓存

排查步骤:

  1. 检查 IndexedDB 是否可用:
    console.log(window.indexedDB); // 应该存在
    
  2. 检查 localforage 初始化:
    import localforage from 'localforage';
    const cache = await localforage.getItem('tracking_cache');
    console.log(cache);
    

4. 版本号不显示

症状: Umami 面板中 version 字段为空

排查步骤:

  1. 检查环境变量:
    console.log(import.meta.env.VITE_APP_VERSION);
    
  2. 检查 vite.config.ts 配置
  3. 重新构建项目:
    npm run build
    

Best Practices (最佳实践)

1. 事件命名规范

推荐:

// 使用 snake_case,包含动作和对象
track="button_click_save"
track="card_hover_feature"
track="input_focus_search"

不推荐:

// 太简短,不明确
track="click"
track="save"

// 太长,冗余
track="user_clicked_the_save_button_in_the_toolbar"

2. 参数设计

推荐:

<!-- 有意义的结构化参数 -->
<Button
  track="toolbar_click_shape"
  track-params='{"shape": "rectangle", "color": "red"}'
/>

不推荐:

<!-- 参数过多或无用 -->
<Button
  track="click"
  track-params='{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, ...}'
/>

3. 性能优化

  • 使用批量上报(减少网络请求)
  • 启用防抖(避免重复上报)
  • 合理配置排除区域(减少无用埋点)
  • 不要在高频事件上埋点(如 mousemove)

4. 隐私保护

  • 不在 track-params 中包含敏感信息(密码、信用卡号)
  • 过滤用户输入的文本内容
  • 遵守 GDPR/CCPA 合规要求

Next Steps

  • 📖 阅读 data-model.md 了解数据结构
  • 📖 阅读 contracts/umami-api.md 了解 API 集成
  • 🛠️ 查看 tasks.md 了解实现细节(待生成)
  • 🧪 运行测试: npm test packages/drawnix/src/services/tracking

FAQ

Q: 自动埋点会影响性能吗? A: 性能开销 <2%,使用事件委托和防抖机制优化。

Q: 可以在生产环境禁用埋点吗? A: 可以,设置 logLevel: 'silent' 并在配置中禁用所有埋点。

Q: 支持移动端吗? A: 支持,touch 事件会映射到 click 事件。

Q: 如何自定义事件名生成规则? A: 修改 tracking-utils.ts 中的 generateAutoEventName() 函数。


Happy Tracking! 🎉