工具分享:實現前端埋點的自動化管理
埋藏點一直是 H5 專案中的重要一環,埋點資料更是後期改善業務和技術最佳化的重要基礎。 【推薦學習:web前端、程式設計教學】
在日常的工作中,常常會有產品或是業務的同學來問,「這個專案現在有哪些埋點?」,「這個埋點用在哪些地方?」像這樣的問題基本上都是問一次查一次程式碼,效率很低。
這也許跟埋點本身的性質有關係。埋點屬於相對獨立的功能,隨著迭代的進行,開發者很難記住埋點的用途。開發者出於自測驗證的需要,也得對專案中的埋設資料加以整理。因此結合當前的場景,可以實現一個工具:透過對程式碼進行掃描,分析埋點相關的程式碼,並對之加以處理,轉化成特定的數據,供後續在其他的管理平台中使用。
實作想法
這個工具大致可以分成三個部分,JSDoc 擷取埋點、路由依賴分析和ESLint 插件。
- JSDoc 是根據 JavaScript 中的註解訊息,產生 API 文件的工具。結合 JSDoc 的這個特性,這個埋點工具把 JSDoc 作為核心部分,用於輸出程式碼中的埋點資料。
- Webpack 外掛程式作為輔助,為 JSDoc 提供路由資訊。
- ESLint 外掛則作為最後的檢驗,確保檔案中的埋點程式碼都有對應的 JSDoc 註解。
自訂JSDoc 標記埋點
我們知道,JSDoc 可以根據程式碼中的註解輸出一份文檔。首先我們自訂一個 JSDoc 的 tag 來標註這是一個埋點的註釋,這樣後續處理時可以過濾掉其他註釋的干擾。結合具體專案中使用的程式碼可以畫出這樣一個流程圖:
下面是具體的程式碼實現的過程。
寫 JSDoc 插件,自訂一個 tag:
// jsdoc.plugin.js // 自定义一个 @log,含有 @log 才是埋点的注释 exports.defineTags = function (dictionary) { dictionary.defineTag('log', { canHaveName: true, onTagged: function (doclet, tag) { doclet.meta.log = tag.text; }, }); };
解析 .ts 和 .vue 檔案。
// jsdoc.plugin.js exports.handlers = { beforeParse: function (e) { // 对文件预处理 if (/.vue/.test(e.filename)) { // 解析 vue 文件 const component = compiler.parseComponent(e.source); // 获取 vue 文件的 script 代码 const ast = parse.parse(component.script.content, { // ... }); } if (/.ts/.test(e.filename)) { // ts 转 js } }, };
自訂 JSDoc 模版。
// publish.js exports.publish = function (taffyData, opts, tutorials) { // ... data().each(function (doclet) { // 有 log 这个 tag 的才是埋点注释 if (doclet.meta && doclet.meta.log) { doclet.tags?.forEach((item) => { // 获取对应的路由地址 }); // 拿到埋点数据 logData.push({}); } }); // 输出 md 文档 fs.writeFileSync(outpath, mdContent, 'utf8'); };
到這裡,已經可以完整地輸出程式碼中的所有埋點了。此時再來看下目前這個工具的能力:
- 自動提取埋點信息,生成埋點文檔:✅
- 自動給埋點註釋添加自定義tag(@log ):❌
- 自動為埋點註解新增上報的埋點資訊:❌
- 自動新增路由資訊:❌
- 自動給埋點註解新增埋點描述資訊:❌
- 自動提示沒有註解的埋點程式碼:❌
透過上面的梳理我們可以看出:
- 需要手動為每個埋點加上註解
- 需要手動去查每個埋點所對應的路由
- 如果忘了給埋點加註解怎麼辦?
做這個工具的初衷,就是為省去一些重複繁瑣的工作,如果為了能自動從程式碼中輸入一份文件而增加了其他一些工作量,這未免有點得不償失。透過這些問題的分析,可以得出以下的解決方案:
- 需要手動為每個埋點加上註解-> 自動填入程式碼-> ESLint fix 功能/ VSCode 外掛程式
- 需要手動去查每個埋點所對應的路由-> 自動找到元件所對應的路由-> Webpack 依賴分析
- 如果忘了給埋點加上註解怎麼辦? -> 忘寫註解有提示 -> ESLint 外掛
到這一步解決問題的方法就已經變得明朗了。接下來讓來看看 webpack 外掛程式與 ESLint 外掛程式的實作過程。
路由依賴分析
webpack 本身自帶依賴分析,輕鬆就能拿到元件間的父子關係。
compiler.hooks.normalModuleFactory.tap('routeAnalysePlugin', (nmf) => { nmf.hooks.afterResolve.tapAsync('routeAnalysePlugin', (result, callback) => { const { resourceResolveData } = result; // 子组件 const path = resourceResolveData.path; // 父组件 const fatherPath = resourceResolveData.context.issuer; // 只获取 vue 文件的依赖关系 if (/.vue/.test(path) && /.vue/.test(fatherPath)) { // 将组件间的父子关系存到变量中 } }); });
把元件之間的依賴關係拼成我們想要的資料格式
[ { "path": "src/views/register-v2/index.vue", "deps": [ { "path": "src/components/landing-banner/index.vue", "deps": [] } ] } // ... ]
组件之间的依赖关系有了,接下来就是找到组件和路由的对应关系,这里我们用 AST 来解析路由文件,获取路由和组件的对应关系。
// 遍历路由文件 for (let i = 0; i < this.routePaths.length; i++) { // ... traverse(ast, { enter(path) { // 找出组件和路由的对应关系 path.node.properties.forEach((item) => { // 组件 if (item.key.name === 'component') { } // 路由地址 if (item.key.name === 'path') { } }); }, }); }
同样地,把组件与路由的映射关系拼成合适的数据格式。
{ "src/views/register-v3/index.vue": "/register" // ... }
再将路由的映射关系和组件间的依赖关系整合到一起,得出每个组件与路由的对应关系。
{ "src/components/landing-banner/index.vue": [ "/register_v2", "/register" //... ] // ... }
因为使用 AST 遍历的方式来解析路由文件,目前支持的解析的路由文件写法有以下四种,基本上满足了当前的场景:
const page1 = (resolve) => { require.ensure( [], () => { resolve(require('page1.vue')); }, 'page1', ); }; const page2 = () => import( /* webpackChunkName: "page2" */ 'page2.vue' ); export default [ { path: '/page1', component: page1 }, { path: '/page2', component: page2 }, { path: '/page3', component: (resolve) => { require.ensure( [], () => { resolve(require('page3.vue')); }, 'page3', ); }, }, { path: '/page4', component: () => import( /* webpackChunkName: "page4" */ 'page4.vue' ), }, ];
再得到了上面的对应关系之后,可以把埋点数据放到传到埋点管理平台上,从而实现一键查询:
编写 ESLint 插件
先来看看代码中埋点上报的三种方式:
// 神策 sdk sensors.track('xxx', {}); // 挂载到 Vue 实例中 this.$sa.track('xxx', {}); // 装饰器 @SensorTrack('xxx', {})
观察上面三种方式,可以知道埋点上报是通过 track 函数和 SensorTrack 函数,所以我们的 ESLint 插件对这两个函数进行校验。
function create(context) { // 调用 track 函数的对象 const checkList = ['sensor', 'sensors', '$sa', 'sa']; return { Literal: function (node) { // ... // 调用埋点函数而缺少注释时 if ( isNoComment && ((isTrack && isSensor) || (is$Track && isThisExpression)) ) { context.report({ node, messageId: 'missingComment', fix: function (fixer) { // 自动修复 }, }); } // 使用修饰器但没有注释时 if ( callee.name === 'SensorTrack' && sourceCode.getCommentsBefore(node).length === 0 ) { context.report({ node, messageId: 'missingComment', fix: function (fixer) { // 自动修复 }, }); } }, }; }
看下完成后的效果:
效果对比
我们再来对比下优化前后的区别:
优化前 | 优化后 | |
---|---|---|
自动提取埋点信息,生成埋点文档 | ✅ | ✅ |
自动给埋点注释添加自定义 tag(@log) | ❌ | ✅ |
自动给埋点注释添加上报的埋点信息 | ❌ | ✅ |
自动给埋点注释添加路由信息 | ❌ | ✅ |
自动给埋点注释添加埋点描述信息 | ❌ | ❌ |
自动提示没有注释的埋点代码 | ❌ | ✅ |
优化之后除了整个流程基本都由工具自动完成,剩下一个埋点描述信息。因为埋点的描述信息只是为了让我们更好地理解这个埋点,本身并不在上报的代码中,所以工具没有办法自动生成,但是我们可以直接在产品提供的埋点文档中拷贝过来完成这一步。
总结
在项目中接入这个工具之后,可以快速地知道项目的埋点有哪些以及各个埋点所在的页面,也方便我们对埋点的梳理,同时利用导出的埋点数据开发后台应用,有效地提升了开发者效率。
这个工具的实现是在 JSDoc、webpack 和 ESLint 插件的加持下水到渠成的,说是水到渠成是因为一开始的想法只是做到第一步,先有个一键查询功能和能够输出一份文档用着先。但是第一版出来后发现要手动去处理这些埋点注释还是比较繁琐,恰巧平常开发中常见的 webpack 插件和 ESLint 插件可以很好地解决这些问题,于是便有路由依赖分析和 ESLint 插件。像是《牧羊少年奇幻之旅》中所说的,“如果你下定决心要做一件事情,整个宇宙都会合力帮助你。”
以上是工具分享:實現前端埋點的自動化管理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

PHP與Vue:完美搭檔的前端開發利器在當今網路快速發展的時代,前端開發變得愈發重要。隨著使用者對網站和應用的體驗要求越來越高,前端開發人員需要使用更有效率和靈活的工具來創建響應式和互動式的介面。 PHP和Vue.js作為前端開發領域的兩個重要技術,搭配起來可以稱得上是完美的利器。本文將探討PHP和Vue的結合,以及詳細的程式碼範例,幫助讀者更好地理解和應用這兩

在前端開發面試中,常見問題涵蓋廣泛,包括HTML/CSS基礎、JavaScript基礎、框架和函式庫、專案經驗、演算法和資料結構、效能最佳化、跨域請求、前端工程化、設計模式以及新技術和趨勢。面試官的問題旨在評估候選人的技術技能、專案經驗以及對行業趨勢的理解。因此,應試者應充分準備這些方面,以展現自己的能力和專業知識。

身為C#開發者,我們的開發工作通常包括前端和後端的開發,而隨著技術的發展和專案的複雜性提高,前端與後端協同開發也變得越來越重要和複雜。本文將分享一些前端與後端協同開發的技巧,以幫助C#開發者更有效率地完成開發工作。確定好介面規範前後端的協同開發離不開API介面的交互。要確保前後端協同開發順利進行,最重要的是定義好介面規格。接口規範涉及到接口的命

Django是一個由Python編寫的web應用框架,它強調快速開發和乾淨方法。儘管Django是web框架,但要回答Django是前端還是後端這個問題,需要深入理解前後端的概念。前端是指使用者直接和互動的介面,後端是指伺服器端的程序,他們透過HTTP協定進行資料的互動。在前端和後端分離的情況下,前後端程式可以獨立開發,分別實現業務邏輯和互動效果,資料的交

Go語言作為一種快速、高效的程式語言,在後端開發領域廣受歡迎。然而,很少有人將Go語言與前端開發聯繫起來。事實上,使用Go語言進行前端開發不僅可以提高效率,還能為開發者帶來全新的視野。本文將探討使用Go語言進行前端開發的可能性,並提供具體的程式碼範例,幫助讀者更了解這一領域。在傳統的前端開發中,通常會使用JavaScript、HTML和CSS來建立使用者介面

web標準的好處有提供更好的跨平台相容性、可訪問性、效能、搜尋引擎排名、開發和維護成本、使用者體驗以及程式碼的可維護性和可重用性。詳細說明:1、跨平台相容性,確保網站在不同的作業系統、瀏覽器和裝置上都能正確顯示和運作;2、提高可訪問性,可以確保網站對所有使用者都是可存取的;3 、加快網站載入速度,使用者可以更快地造訪和瀏覽網站,提供更好的使用者體驗;4、提高搜尋引擎排名等等。

web標準預設的連接埠有:1、HTTP,預設連接埠號碼為80;2、HTTPS,預設連接埠號碼為443;3、FTP,預設連接埠號碼為21;4、SSH,預設連接埠號碼為22;5、Telnet ,預設連接埠號碼為23;6、SMTP,預設連接埠號碼為25;7、POP3,預設連接埠號碼為110;8、IMAP,預設連接埠號碼為143;9、DNS,預設連接埠號碼為53;10、RDP ,預設連接埠號碼為3389等等。

實作即時通訊的方法有WebSocket、Long Polling、Server-Sent Events、WebRTC等等。詳細介紹:1、WebSocket,它可以在客戶端和伺服器之間建立持久連接,實現即時的雙向通信,前端可以使用WebSocket API來創建WebSocket連接,並透過發送和接收訊息來實現即時通訊;2、Long Polling,是一種模擬即時通訊的技術等等
