# gd-tracker

## 1. `gd-tracker-cli` 使用说明

### 1.1 `gd-tracker-cli` 命令接口
```bash
# (1) 获取所有可支持的项目名
npx gd-tracker-cli list

# (2) 指定项目名初始化一个埋点项目
npx gd-tracker-cli gen -n gd_web                                        # -n: 指定一个项目名

# (3) 指定项目名初始化多个埋点项目
npx gd-tracker-cli gen -n gd_web focodesign_web                         # -n: 指定多个项目名

# (4) 指定项目名和文件的生成目录初始化一个埋点项目
# 默认不指定 -d 那么生成的代码就在 ./src/wind 下面
npx gd-tracker-cli gen -n gd_web -d ./src/wind                          # -n: 指定项目名; -d: 指定文件的生成目录 (相对路径)

# (5) 忽略缓存强行从线上拉取 schemas 生成代码
npx gd-tracker-cli gen -n gd_web -d ./src/wind -f                       # -f: 忽略缓存强行从线上拉取 schemas 生成代码

# (6) 开启验证服务
# validate 验证服务需要用到  cache.xxx.zip 缓存文件中的 schemas.json 做验证
npx gd-tracker-cli validate -d ./src/wind                               # -d: 指定存放 .cache.xxx.zip 的目录路径 (相对路径)
npx gd-tracker-cli validate -p 6427 -d ./src/wind                       # -p: 不指定默认是 6427
```

### 1.2 `gd-tracker-cli` 的 `package.json` 配置
以下配置用于锁定 `gd-tracker-cli` 生成的当前次埋点 API 文件
```json
{
    "scripts": {
        "postinstall": "npx gd-tracker-cli gen -n xxx -d ./src/wind"    // 写你自己的项目名和 .cache.xxx.zip 的目录路径
    }
}
```

### 1.3 `gd-tracker-cli` 生成的产物介绍

#### 1.3.2 生成代码
```bash
# 指定项目名初始化多个埋点项目
node ./bin/index.js gen -n gd_web focodesign_web

# [gd-tracker-cli] 正在生成 gd_web、focodesign_web 的埋点 API 文件
# [gd-tracker-cli] fetching schemas from https://x.gdm.gaoding.com/api/wind/schemas/gd_web/
# [gd-tracker-cli] fetching schemas from https://x.gdm.gaoding.com/api/wind/schemas/focodesign_web/
# [gd-tracker-cli] 生成 gd_web 的埋点 API 文件成功！
# [gd-tracker-cli] 生成的埋点 API 文件路径为：/Users/jun/workspace/project/gd-tracker/src/wind/api/gd_web/index.ts
# [gd-tracker-cli] 生成 focodesign_web 的埋点 API 文件成功！
# [gd-tracker-cli] 生成的埋点 API 文件路径为：/Users/jun/workspace/project/gd-tracker/src/wind/api/focodesign_web/index.ts
# [gd-tracker-cli] 生成埋点配置文件成功！
# [gd-tracker-cli] 生成的埋点配置文件路径为：/Users/jun/workspace/project/gd-tracker/src/wind/index.ts
```

#### 1.3.3 生成产物 (TS 版本的代码)
```bash
tree ./src/wind -C -L 3 -a

# ./src/wind
# ├── .cache.2022.11.24.13.30.14.zip                    # gd-tracker-cli 的缓存 (需要随用户的代码一起提交到 Git 的仓库)
# ├── GD-TRACKER.md                                     # 您现在阅读到的这个 md 文件
# ├── api                                               # 根据生成的 TS 版本的埋点 API 代码的目录
# │   ├── focodesign_web.ts
# │   ├── gd_web.ts
# │   └── index.ts                                      # 埋点 API 代码出口文件
# └── index.ts                                          # gd-tracker 的配置文件模板
```

##### 1.3.3.1 `.cache.2022.11.08.10.01.43.zip` 缓存介绍
`gd-tracker-cli` 埋点 API 代码的逻辑是请求 Schema 平台的接口生成的，由于接口的数据会发生变化 (埋点需求的变更)，因此每次生成的代码可能会不一样。`.cache.xxx.zip` 文件是 `gd-tracker-cli` 生成代码时用于记录当前版本埋点 API 代码和还原代码用的。其结构如下：
```bash
tree ./bin/.cache -C -L 5 -a

# ./bin/.cache                                          # 总的缓存目录
# └── 2022.11.24.13.33.30                               # 不同时间根据线上 schemas 生成的 代码的记录
#     ├── GD-TRACKER.md                                 # 介绍文件
#     ├── api                                           # 根据生成的 TS 版本的埋点 API 代码的目录
#     │   ├── focodesign_web                            # 项目名
#     │   │   ├── index.ts                              # 根据线上 schemas 生成的 TS 版本的埋点 API 代码
#     │   │   └── schemas.json                          # gd-tracker-cli 请求 Schema 平台的接口返回的数据
#     │   ├── gd_web
#     │   │   ├── index.ts
#     │   │   └── schemas.json
#     │   └── index.ts
#     ├── db.json                                       # 记录必要文件的哈希值
#     └── index.ts                                      # gd-tracker 的配置文件模板
```
`.cache.xxx.zip` 是一个后压缩的文件，因此用户是不能更改其内容的，请不要更改 `.cache.xxx.zip` 的文件命名，`gd-tracker-cli` 按照 `/^\.cache\.(\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2})\.zip$/` 的正则匹配来 `.cache.xxx.zip` 文件。  
用户将其提交到自己代码仓库的 Git 地址后可以根据需要还原 `.cache.xxx.zip` 不同中时间生成的埋点 API 代码。默认情况下只要有 `.cache.xxx.zip` 存在用户的代码仓库里，`gd-tracker-cli` 就不会去线上拉取数据生成新的代码，如果想要从线上拉取数据生成新的代码可以用 `npx gd-tracker-cli gen -n xxx -f` 命令生成。

##### 1.3.3.1 `src/wind/api/*.ts` TS 版本的埋点 API 代码介绍
以下代码是通过 Schema 平台的接口生成的，一个埋点的 API 包括埋点的函数实现和函数类型的声明，`api.ts` 是用户不可更改的。如果更改了想要还原代码可以通过 `.cache.xxx.zip` 还原。
```ts
import { trackerWind } from '@gaoding/gd-tracker';

// trackWrite 的类型定义
export declare namespace Tracker {

    export namespace Write {

        export interface IDetail {
            platform_id?: string;    // 平台
            template_classify?: string;    // 模板分类
            template_group_id?: string;    // 模板组id
            template_id: string;    // 模板id
            template_nature: string;    // 模板属性
            template_scen?: string;    // 模板场景
            template_suit_id?: string;    // 套装id
            work_id: string;    // 作品id
        }

        export interface Api {
            (detail: IDetail, callback?: (result: null | Error) => any): void;
        }
    }
}

// 模板下载
export const trackWrite: Tracker.Write.Api = (option, callback) => {
    const detail = Object.assign({}, option, { event_id: 5 });
    return trackerWind.trackEvent('write', detail, callback);
};
```

##### 1.3.3.2 `src/wind/api/index.ts` TS 版本的埋点 API 代码出口文件
```ts
import * as gdWeb from './gd_web';
import * as focodesignWeb from './focodesign_web';

export type GdWeb = typeof gdWeb;
export type FocodesignWeb = typeof focodesignWeb;

export type UnionWind = {
    gdWeb: GdWeb;
    focodesignWeb: FocodesignWeb;
};

export const prototype: UnionWind = {
    gdWeb,
    focodesignWeb,
};

// 函数重载
export function createWindAPI(name: 'gd_web'): UnionWind['gdWeb'] & UnionWind;
export function createWindAPI(name: 'focodesign_web'): UnionWind['focodesignWeb'] & UnionWind;

// 创建埋点 API 接口调用的对象
export function createWindAPI(name: 'gd_web' | 'focodesign_web') {
    const underline = /([^_])(?:_+([^_]))/g;
    const camelCase = (str: string) => str.replace(underline, ($0, $1, $2) => $1 + $2.toUpperCase());
    const self = prototype[camelCase(name)];
    const result = Object.assign(prototype, self);
    return result;
};

// createWindAPI 例子
// const windAPI = createWindAPI('gd_web');            // 指定默认调用的项目名 (参数和埋点 SDK 初始化的项目名一样的)
// windAPI.trackWrite(/*...*/);                        // 默认调用 (这个例子里默认调用的方法就是 src/wind/api/gd_web.ts 文件中的 trackWrite 方法)
// windAPI.gdWeb.trackWrite(/*...*/);                  // 指定项目名调用
// windAPI.focodesignWeb.trackAddHotSaved(/*...*/);    // 指定项目名调用
```

##### 1.3.3.3 `src/wind/index.ts` gd-tracker 的配置文件模板
```ts
// 埋点插件列表
const createPlugins = (app: any) => {
    return [
        'utm-data-tracker', // utm 插件
        'page-duration-tracker', // 页面停留时长埋点
        [
            'router-change-tracker',    // 上报 page_visit 事件，默认上报的事件 id 是 39003，可以配置 (参考文档)
            {
                app, // app 为 vue 实例
                eventId: 39003, // [非必填] eventId 对应项目给的 page_visit 的事件 id，不填默认 39003
                change(from, to) {  // [非必填] 路由改变的回调，from & to 来着 vue-router 的路由参数
                    return {    // [非必填] 返回的数据会添加到 page_visit 的 detail 业务数据层下，根据需要自行实现 change 方法
                        
                    };
                },
            },
        ],
    ];
};

// Wind 选项
const createWind = (app: any) => {
    return {
        project: 'gd_web',    // 埋点项目名，@数据中台开通埋点项目， @惊鸿
        version: PROJECT_VERSION,   // 项目版本，无垠数据公共业务数据字段。
        batch: true,    // 是否在登录后才上报埋点数据 (手动调用 trackerWind.login 方法后才开始上报埋点数据)
        login: false,   // 是否在登录后才上报埋点数据
        env: TRACKER_ENV,   // 环境变量 (可选值: dev, fat, stage, prod)
        showLog: SHOW_LOG,  // 是否在控制台打印埋点信息
        plugins: createPlugins(app), // 埋点插件列表
        isValidate: window.location.href.includes('//localhost'),   // 是否对埋点数据进行本地验证
        validateURL: 'http://localhost:6427/wind',                  // 对埋点数据进行本地验证的地址
        // channel: createChannel(),   // 渠道信息
        // organization: createOrganization(), // 创建组织信息
    };
};

export const windAPI = createWindAPI('gd_web');

// 埋点 SDK 初始化方法
export const gdTrackerInit = (app: any) => {
    const wind = createWind(app);
    tracker.setup({ wind }, IS_PROD, DEBUG_MODE);
};

export default gdTrackerInit;
```

### 1.4 `gd-tracker-cli` 的本地埋点数据校验

#### 1.4.1 启动 `gd-tracker-cli` 提供本地数据校验的服务
```bash
npx gd-tracker-cli validate -p 6427 -d ./src/wind                                       # validate 验证服务需要用到  cache.xxx.zip 缓存文件中的 schemas.json 做验证

# [gd-tracker-cli] Validator server is run in http://localhost:6427.
# [gd-tracker-cli] The validateURL is http://localhost:6427/wind                        # 本地数据验证服务的地址
# [gd-tracker-cli] You can get the project schema by: http://localhost:6427/schemas     # 从这里可以访问 gd-tracker-cli 请求 Schema 平台的接口返回的数据
```

#### 1.4.2 和本地数据校验的服务有关的配置
```ts
// Wind 选项
const createWind = (app: any) => {
    return {
        // ...
        env: 'dev',                                                 // 尽在 env 为 dev 的环境下才生效
        isValidate: window.location.href.includes('//localhost'),   // 是否对埋点数据进行本地验证
        validateURL: 'http://localhost:6427/wind',                  // 对埋点数据进行本地验证的地址
    };
};

export const gdTrackerInit = (app: any) => {
    const wind = createWind(app);
    tracker.setup({ wind }, IS_PROD, DEBUG_MODE);
};
```
