# 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 脚本: ```html ``` ### 2. 安装依赖 ```bash # 项目依赖已包含,无需额外安装 npm install ``` --- ## Basic Usage (基础埋点) ### Step 1: 在 Drawnix 中启用埋点插件 修改 `packages/drawnix/src/drawnix.tsx`: ```typescript import { withTracking } from './plugins/tracking'; // 在其他插件后添加 withTracking const editor = withMind( withDraw( withFreehand( withTracking( // 其他插件... ) ) ) ); ``` ### Step 2: 添加手动埋点属性 在任意 React 组件中使用 `track` 属性: ```tsx // 示例: UnifiedToolbar.tsx export const UnifiedToolbar = () => { return (
{/* 基础埋点 */} {/* 带参数的埋点 */} {/* 不埋点 */}
); }; ``` ### 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` 属性: ```typescript // packages/drawnix/src/drawnix.tsx const editor = withTracking( // ... other plugins { autoTrack: true // 启用自动埋点 } ); ``` **效果**: - 所有 ` // 自动生成事件名: auto_click_save-btn 或 auto_click_保存 ``` ### 2. 排除特定元素 使用 `data-track-ignore` 属性排除埋点: ```tsx ``` ### 3. 支持其他事件类型 除了 click,还支持 hover、focus 等事件: ```tsx // Hover 埋点 Feature Card // Focus 埋点 // 同时支持多种事件 ``` --- ## Configuration (配置) ### 全局配置 创建 `packages/drawnix/src/config/tracking.config.ts`: ```typescript import type { TrackConfig } from '../types/tracking.types'; export const trackingConfig: Partial = { 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' // 自定义排除类 ] }; ``` 应用配置: ```typescript // drawnix.tsx import { trackingConfig } from './config/tracking.config'; const editor = withTracking( // ... plugins trackingConfig ); ``` ### 环境变量配置 在 `vite.config.ts` 中注入版本号: ```typescript // 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 (测试) ### 开发环境测试 启用调试模式: ```typescript 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 ``` ### 单元测试 ```typescript // 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 测试 ```typescript // 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 是否加载: ```javascript console.log(window.umami); // 应该是一个对象 ``` 2. 检查插件是否启用: ```typescript // drawnix.tsx 中是否调用了 withTracking ``` 3. 检查元素是否被排除: ```typescript // 元素是否在 nav/header/footer 内? // 元素是否有 data-track-ignore 属性? ``` 4. 检查防抖: ```typescript // 是否在 500ms 内重复点击? ``` ### 2. 批量上报不触发 **症状**: 事件队列一直累积,不上报 **排查步骤**: 1. 检查批量配置: ```typescript batchConfig: { enabled: true // 是否启用? } ``` 2. 检查网络连接: ```bash curl https://your-umami-domain/api/send ``` 3. 查看控制台错误: ```javascript // 是否有 CORS 错误? // 是否有 401/403 认证错误? ``` ### 3. 缓存不工作 **症状**: 离线时事件丢失,未缓存 **排查步骤**: 1. 检查 IndexedDB 是否可用: ```javascript console.log(window.indexedDB); // 应该存在 ``` 2. 检查 localforage 初始化: ```typescript import localforage from 'localforage'; const cache = await localforage.getItem('tracking_cache'); console.log(cache); ``` ### 4. 版本号不显示 **症状**: Umami 面板中 `version` 字段为空 **排查步骤**: 1. 检查环境变量: ```javascript console.log(import.meta.env.VITE_APP_VERSION); ``` 2. 检查 vite.config.ts 配置 3. 重新构建项目: ```bash npm run build ``` --- ## Best Practices (最佳实践) ### 1. 事件命名规范 **推荐**: ```typescript // 使用 snake_case,包含动作和对象 track="button_click_save" track="card_hover_feature" track="input_focus_search" ``` **不推荐**: ```typescript // 太简短,不明确 track="click" track="save" // 太长,冗余 track="user_clicked_the_save_button_in_the_toolbar" ``` ### 2. 参数设计 **推荐**: ```tsx