亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長資訊網(wǎng)
    最全最豐富的資訊網(wǎng)站

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

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

    埋點(diǎn)一直是 H5 項(xiàng)目中的重要一環(huán),埋點(diǎn)數(shù)據(jù)更是后期改善業(yè)務(wù)和技術(shù)優(yōu)化的重要基礎(chǔ)。【推薦學(xué)習(xí):web前端、編程教學(xué)】

    在日常的工作中,經(jīng)常會有產(chǎn)品或者業(yè)務(wù)的同學(xué)來問,“這個項(xiàng)目現(xiàn)在有哪些埋點(diǎn)?”,“這個埋點(diǎn)用在哪些地方?”像這樣的問題基本上都是問一次查一次代碼,效率很低。

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

    這也許跟埋點(diǎn)本身的性質(zhì)有關(guān)系。埋點(diǎn)屬于相對獨(dú)立的功能,隨著迭代的進(jìn)行,開發(fā)者很難記住埋點(diǎn)的用途。開發(fā)者出于自測驗(yàn)證的需要,也得對項(xiàng)目中的埋點(diǎn)數(shù)據(jù)加以整理。因此結(jié)合當(dāng)前的場景,可以實(shí)現(xiàn)一個工具:通過對代碼進(jìn)行掃描,分析埋點(diǎn)相關(guān)的代碼,并對之加以處理,轉(zhuǎn)化成特定的數(shù)據(jù),供后續(xù)在其他的管理平臺中使用。

    實(shí)現(xiàn)思路

    這個工具大致可以分成三個部分,JSDoc 提取埋點(diǎn)、路由依賴分析和 ESLint 插件。

    • JSDoc 是根據(jù) JavaScript 中的注釋信息,生成 API 文檔的一個工具。結(jié)合 JSDoc 的這一個特性,這個埋點(diǎn)工具把 JSDoc 作為核心部分,用于輸出代碼中的埋點(diǎn)數(shù)據(jù)。
    • Webpack 插件作為輔助,為 JSDoc 提供路由信息。
    • ESLint 插件則作為最后的檢驗(yàn),確保文件中的埋點(diǎn)代碼都有對應(yīng)的 JSDoc 注釋。

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

    自定義 JSDoc 標(biāo)記埋點(diǎn)

    我們知道,JSDoc 可以根據(jù)代碼中的注釋輸出一份文檔。首先我們自定義一個 JSDoc 的 tag 來標(biāo)注這是一個埋點(diǎn)的注釋,這樣后續(xù)處理時(shí)可以過濾掉其他注釋的干擾。結(jié)合具體項(xiàng)目中使用的代碼可以畫出這樣一個流程圖:

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

    下面是具體的代碼實(shí)現(xiàn)的過程。

    編寫 JSDoc 插件,自定義一個 tag:

    // jsdoc.plugin.js // 自定義一個 @log,含有 @log 才是埋點(diǎn)的注釋 exports.defineTags = function (dictionary) {   dictionary.defineTag('log', {     canHaveName: true,     onTagged: function (doclet, tag) {       doclet.meta.log = tag.text;     },   }); };
    登錄后復(fù)制

    解析 .ts 和 .vue 文件。

    // jsdoc.plugin.js exports.handlers = {   beforeParse: function (e) {     // 對文件預(yù)處理     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 轉(zhuǎn) js     }   }, };
    登錄后復(fù)制

    自定義 JSDoc 模版。

    // publish.js exports.publish = function (taffyData, opts, tutorials) {   // ...   data().each(function (doclet) {     // 有 log 這個 tag 的才是埋點(diǎn)注釋     if (doclet.meta && doclet.meta.log) {       doclet.tags?.forEach((item) => {         // 獲取對應(yīng)的路由地址       });        // 拿到埋點(diǎn)數(shù)據(jù)       logData.push({});     }   });    // 輸出 md 文檔   fs.writeFileSync(outpath, mdContent, 'utf8'); };
    登錄后復(fù)制

    到這里,已經(jīng)可以完整地輸出代碼中的所有埋點(diǎn)了。此時(shí)再來看下目前這個工具的能力:

    • 自動提取埋點(diǎn)信息,生成埋點(diǎn)文檔:✅
    • 自動給埋點(diǎn)注釋添加自定義 tag(@log):❌
    • 自動給埋點(diǎn)注釋添加上報(bào)的埋點(diǎn)信息:❌
    • 自動給埋點(diǎn)注釋添加路由信息:❌
    • 自動給埋點(diǎn)注釋添加埋點(diǎn)描述信息:❌
    • 自動提示沒有注釋的埋點(diǎn)代碼:❌

    通過上面的梳理我們可以看出:

    • 需要手動給每個埋點(diǎn)加上注釋
    • 需要手動去查每個埋點(diǎn)所對應(yīng)的路由
    • 如果忘了給埋點(diǎn)加注釋怎么辦?

    做這個工具的初衷,就是為省去一些重復(fù)繁瑣的工作,如果為了能自動從代碼中輸入一份文檔而增加了其他一些工作量,這未免有點(diǎn)得不償失。通過對這些問題的分析,可以得出以下的解決方案:

    • 需要手動給每個埋點(diǎn)加上注釋 -> 自動填充代碼 -> ESLint fix 功能 / VSCode 插件
    • 需要手動去查每個埋點(diǎn)所對應(yīng)的路由 -> 自動找到組件所對應(yīng)的路由 -> Webpack 依賴分析
    • 如果忘了給埋點(diǎn)加注釋怎么辦?-> 忘寫注釋有提示 -> ESLint 插件

    到這一步解決問題的方法就已經(jīng)變得明朗了。接下來讓看一下 webpack 插件與 ESLint 插件的實(shí)現(xiàn)過程。

    路由依賴分析

    webpack 本身自帶依賴分析,輕松就能拿到組件間的父子關(guān)系。

    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 文件的依賴關(guān)系     if (/.vue/.test(path) && /.vue/.test(fatherPath)) {       // 將組件間的父子關(guān)系存到變量中     }   }); });
    登錄后復(fù)制

    把組件之間的依賴關(guān)系拼成我們想要的數(shù)據(jù)格式

    [   {     "path": "src/views/register-v2/index.vue",     "deps": [       {         "path": "src/components/landing-banner/index.vue",         "deps": []       }     ]   }   // ... ]
    登錄后復(fù)制

    組件之間的依賴關(guān)系有了,接下來就是找到組件和路由的對應(yīng)關(guān)系,這里我們用 AST 來解析路由文件,獲取路由和組件的對應(yīng)關(guān)系。

    // 遍歷路由文件 for (let i = 0; i < this.routePaths.length; i++) {   // ...   traverse(ast, {     enter(path) {       // 找出組件和路由的對應(yīng)關(guān)系       path.node.properties.forEach((item) => {         // 組件         if (item.key.name === 'component') {         }          // 路由地址         if (item.key.name === 'path') {         }       });     },   }); }
    登錄后復(fù)制

    同樣地,把組件與路由的映射關(guān)系拼成合適的數(shù)據(jù)格式。

    {   "src/views/register-v3/index.vue": "/register"   // ... }
    登錄后復(fù)制

    再將路由的映射關(guān)系和組件間的依賴關(guān)系整合到一起,得出每個組件與路由的對應(yīng)關(guān)系。

    {   "src/components/landing-banner/index.vue": [     "/register_v2",     "/register"     //...   ]   // ... }
    登錄后復(fù)制

    因?yàn)槭褂?AST 遍歷的方式來解析路由文件,目前支持的解析的路由文件寫法有以下四種,基本上滿足了當(dāng)前的場景:

    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'       ),   }, ];
    登錄后復(fù)制

    再得到了上面的對應(yīng)關(guān)系之后,可以把埋點(diǎn)數(shù)據(jù)放到傳到埋點(diǎn)管理平臺上,從而實(shí)現(xiàn)一鍵查詢:

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

    編寫 ESLint 插件

    先來看看代碼中埋點(diǎn)上報(bào)的三種方式:

    // 神策 sdk sensors.track('xxx', {});  // 掛載到 Vue 實(shí)例中 this.$sa.track('xxx', {});  // 裝飾器 @SensorTrack('xxx', {})
    登錄后復(fù)制

    觀察上面三種方式,可以知道埋點(diǎn)上報(bào)是通過 track 函數(shù)和 SensorTrack 函數(shù),所以我們的 ESLint 插件對這兩個函數(shù)進(jìn)行校驗(yàn)。

    function create(context) {   // 調(diào)用 track 函數(shù)的對象   const checkList = ['sensor', 'sensors', '$sa', 'sa'];    return {     Literal: function (node) {       // ...       // 調(diào)用埋點(diǎn)函數(shù)而缺少注釋時(shí)       if (         isNoComment &&         ((isTrack && isSensor) || (is$Track && isThisExpression))       ) {         context.report({           node,           messageId: 'missingComment',           fix: function (fixer) {             // 自動修復(fù)           },         });       }        // 使用修飾器但沒有注釋時(shí)       if (         callee.name === 'SensorTrack' &&         sourceCode.getCommentsBefore(node).length === 0       ) {         context.report({           node,           messageId: 'missingComment',           fix: function (fixer) {             // 自動修復(fù)           },         });       }     },   }; }
    登錄后復(fù)制

    看下完成后的效果:

    工具分享:實(shí)現(xiàn)前端埋點(diǎn)的自動化管理

    效果對比

    我們再來對比下優(yōu)化前后的區(qū)別:

    優(yōu)化前 優(yōu)化后
    自動提取埋點(diǎn)信息,生成埋點(diǎn)文檔
    自動給埋點(diǎn)注釋添加自定義 tag(@log)
    自動給埋點(diǎn)注釋添加上報(bào)的埋點(diǎn)信息
    自動給埋點(diǎn)注釋添加路由信息
    自動給埋點(diǎn)注釋添加埋點(diǎn)描述信息
    自動提示沒有注釋的埋點(diǎn)代碼

    優(yōu)化之后除了整個流程基本都由工具自動完成,剩下一個埋點(diǎn)描述信息。因?yàn)槁顸c(diǎn)的描述信息只是為了讓我們更好地理解這個埋點(diǎn),本身并不在上報(bào)的代碼中,所以工具沒有辦法自動生成,但是我們可以直接在產(chǎn)品提供的埋點(diǎn)文檔中拷貝過來完成這一步。

    總結(jié)

    在項(xiàng)目中接入這個工具之后,可以快速地知道項(xiàng)目的埋點(diǎn)有哪些以及各個埋點(diǎn)所在的頁面,也方便我們對埋點(diǎn)的梳理,同時(shí)利用導(dǎo)出的埋點(diǎn)數(shù)據(jù)開發(fā)后臺應(yīng)用,有效地提升了開發(fā)者效率。

    這個工具的實(shí)現(xiàn)是在 JSDoc、webpack 和 ESLint 插件的加持下水到渠成的,說是水到渠成是因?yàn)橐婚_始的想法只是做到第一步,先有個一鍵查詢功能和能夠輸出一份文檔用著先。但是第一版出來后發(fā)現(xiàn)要手動去處理這些埋點(diǎn)注釋還是比較繁瑣,恰巧平常開發(fā)中常見的 webpack 插件和 ESLint 插件可以很好地解決這些問題,于是便有路由依賴分析和 ESLint 插件。像是《牧羊少年奇幻之旅》中所說的,“如果你下定決心要做一件事情,整個宇宙都會合力幫助你。”

    【推薦學(xué)習(xí):web前端開發(fā)、編程基礎(chǔ)視頻教程】

    贊(0)
    分享到: 更多 (0)
    網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號