站長資訊網
        最全最豐富的資訊網站

        工具分享:實現前端埋點的自動化管理

        工具分享:實現前端埋點的自動化管理

        前端(vue)入門到精通課程,老師在線輔導:聯系老師
        Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調試工具:點擊使用

        埋點一直是 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 插件。像是《牧羊少年奇幻之旅》中所說的,“如果你下定決心要做一件事情,整個宇宙都會合力幫助你。”

        【推薦學習:web前端開發、編程基礎視頻教程】

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 日韩精品区一区二区三VR| 国产精品毛片一区二区三区| 欧美性videos高清精品| 91精品无码久久久久久五月天 | 国产香蕉精品视频在| 精品无码人妻夜人多侵犯18| 正在播放酒店精品少妇约| 久久se这里只有精品| 国产精品国产欧美综合一区| 欧美精品国产一区二区| 97久久久久人妻精品专区| 久久精品国产亚洲AV无码偷窥| 亚洲精品无码AV中文字幕电影网站| 精品久久久无码中文字幕| 国产欧美一区二区精品性色99 | 国产91久久精品一区二区| 国产99视频精品免费专区| 欧美精品hdvideosex4k| 亚洲精品无码乱码成人| 亚洲精品无码成人片在线观看 | 99re国产精品视频首页| 高清免费久久午夜精品| 91麻豆精品国产自产在线观看一区 | 99精品在线播放| 国产精品自在线拍国产| 久久久久人妻精品一区| 四虎影视永久在线观看精品| 亚洲精品无码久久久久久| 人妻少妇看A偷人无码精品| 欧美成人精品欧美一级乱黄一区二区精品在线 | 国产亚洲欧美精品永久| 久久久精品国产sm调教网站| 精品亚洲A∨无码一区二区三区| 久久久无码人妻精品无码| 久久精品毛片免费观看| 久久精品aⅴ无码中文字字幕不卡| 国产亚洲精品岁国产微拍精品| 国产精品亲子乱子伦xxxx裸| 99精品国产一区二区三区2021| 91精品视频网站| 91精品无码久久久久久五月天 |