关于什么是SPM,戳
任何不以自己的业务为基础的模型的都是耍流氓
为什么需要
- 耽误时间
- 容易出错
- 需求满足捉襟见肘
当前自身业务中的埋点形态极为负责,开发链路涉及到前端、产品、数据多方协作,也没有统一的规范及沟通机制,唯一有的就是一个da文档平台(可以录入名字、以及基础的打点验证),而这极大的影响了前端的开发效率,同时在埋点过程中出错的概率也极高,同时对于一些资源位的统计,当前是在埋点中手动增加参数(嗯,你没看错)。
所以根据当前的基建情况,总结出一套更加高效的打点方案——spm(基于淘宝的spm概念)
优化现有协作流程
当前我们是这样的:产品提出指标要求-> 数据产品制定出打点文档(每个点的名称、参数等等)-> 开发侵入代码添加埋点 -> 产品验收 -> 上线
期望的流程: 产品整理出特殊埋点(主要指无页面跳转) -> 开发自行打入相关埋点(包括spm和自定义埋点名称)-> 落地文档给数据、产品查阅 -> 产品验收 -> 上线
怎么做
- 制定一个埋点规范
- 跳转行为前端主动点击埋点,并命名b\c参数,例如一个点大概是这样的
`${页面路由}.${b的定义}.${c的定义}.${时间戳}`
- 非跳转行为以及需要特殊,产品给出所需要统计的参数,使用通用的action,并生成文档落地
- 打点SDK,用于在业务开发中便捷使用,提供一个容器型的组件及方法,供业务方快速接入
- 落地打点文档,供产品数据查阅
小程序spm SDK基本设计
小程序对于dom的操作不如web灵活,那如何表现出小程序的b、c嵌套关系呢——事件捕获
view
<view id="m-da-anchor" class="mclass" style="{{mstyle}}" data-b="{{b}}" data-c="{{c}}" capture-bind:tap="captureTap"> <slot></slot> </view>
index.js
// index.js captureTap() { const app = getApp(); if (this.data.b) { app.DA_SPM_B = this.data.b; } if (this.data.c) { app.DA_SPM_C = this.data.c; } }
在事件捕获阶段储存b\c点的信息。
app.js
export function initSpm() { const rewritePath = (originFuncs, params) => { const { url } = params; const app = getApp(); if (app.DA_SPM_B && app.DA_SPM_C) { try { params.url = generateSpmUrl(url); originFuncs.call(wx, params); app.DA_SPM_B = undefined; app.DA_SPM_C = undefined; } catch (error) { captureError('spm跳转失败', params, { logger: 'da', }); originFuncs.call(wx, params); } } else { originFuncs.call(wx, params); } }; Object.defineProperties(wx, { navigateTo: { value: rewritePath.bind(wx, wx.navigateTo), }, switchTab: { value: rewritePath.bind(wx, wx.switchTab), }, redirectTo: { value: rewritePath.bind(wx, wx.redirectTo), }, reLaunch: { value: rewritePath.bind(wx, wx.reLaunch), }, }); }
重写原生的跳转行为,将缓存的信息携带至路由上。
以上的实现目前主要发现两个问题:
- 层级会响应的加深
- 不能使用navigator的组件
如何落地文档
基于gitlab page生成打点说明文档。收集每个路由下的说明文档(格式约定),通过ci生产一份单独的说明文档
大概长这个样子:
最后
以上的实现是基于当前的基建水平的进一步抽象,主要目的是:降低埋点复杂度和资源位打点问题。