日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
為啥套娃?聊聊Babel、Jscodeshift和阿里媽媽的Gogocode

首先,我是《babel 插件通關(guān)秘籍》 掘金小冊的作者,對 babel 有源碼級的掌握,算是有資格討論這個話題。

創(chuàng)新互聯(lián)是一家專注于網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)與策劃設(shè)計,溫宿網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:溫宿等地區(qū)。溫宿做網(wǎng)站價格咨詢:13518219792

本來會探討以下話題:

  • babel 是怎么轉(zhuǎn)換代碼的
  • jscodeshift 是怎么轉(zhuǎn)換代碼的
  • babel 和 jscodeshift 的區(qū)別
  • 為什么不推薦 gogocode

babel 是怎么轉(zhuǎn)換代碼的

babel 編譯流程分為 3 步:parse、transform、generate

  • parse:把源碼轉(zhuǎn)成 AST,babel parser(babylon) 支持 esnext 語法,可通過插件支持 typescript、jsx、flow 等語法
  • transform:對 AST 進行轉(zhuǎn)換,通過 visitor 對不同的 AST 進行處理
  • generate:打印轉(zhuǎn)換后的 AST 為目標代碼,并生成 sourcemap

轉(zhuǎn)換插件這樣寫(小冊中的一個 linter 的案例):

 
 
 
 
  1. const { declare } = require('@babel/helper-plugin-utils'); 
  2.  
  3. const noFuncAssignLint = declare((api, options, dirname) => { 
  4.     api.assertVersion(7); 
  5.  
  6.     return { 
  7.         pre(file) { 
  8.             file.set('errors', []); 
  9.         }, 
  10.         visitor: { 
  11.             AssignmentExpression(path, state) { 
  12.                 const errors = state.file.get('errors'); 
  13.                 const assignTarget = path.get('left').toString() 
  14.                 const binding = path.scope.getBinding(assignTarget); 
  15.                 if (binding) { 
  16.                     if (binding.path.isFunctionDeclaration() || binding.path.isFunctionExpression()) { 
  17.                         const tmp = Error.stackTraceLimit; 
  18.                         Error.stackTraceLimit = 0; 
  19.                         errors.push(path.buildCodeFrameError('can not reassign to function', Error)); 
  20.                         Error.stackTraceLimit = tmp; 
  21.                     } 
  22.                 } 
  23.             } 
  24.         }, 
  25.         post(file) { 
  26.             console.log(file.get('errors')); 
  27.         } 
  28.     } 
  29. }); 
  30.  
  31. module.exports = noFuncAssignLint; 

聲明 visitor 函數(shù),然后在遍歷的過程中會被調(diào)用,其中可以拿到 path 和 state 的 api:

path 是節(jié)點之間的關(guān)系,每個 path關(guān)聯(lián)父節(jié)點和當前節(jié)點,path 對象構(gòu)成一條從當前節(jié)點到根結(jié)點的路徑。state 是遍歷過程中的共享數(shù)據(jù)的機制。

通過 path 的一系列增刪改查 AST 的 api 來完成 transform。

比如下列 api:

 
 
 
 
  1. getSibling(key)  
  2. getNextSibling() 
  3. getPrevSibling() 
  4. getAllPrevSiblings() 
  5. getAllNextSiblings() 
  6. isXxx(opts) 
  7. assertXxx(opts) 
  8.  
  9. insertBefore(nodes) 
  10. insertAfter(nodes) 
  11. replaceWith(replacement) 
  12. replaceWithMultiple(nodes) 
  13. replaceWithSourceString(replacement) 
  14. remove() 

jscodeshift 是怎么轉(zhuǎn)換代碼的

jscodeshift 也是代碼轉(zhuǎn)換的工具,但是 api 風格不同,是主動查找 AST,然后修改成新的 AST,最后生成代碼的形式:

 
 
 
 
  1. module.exports = function(fileInfo, api) { 
  2.   return api.jscodeshift(fileInfo.source) 
  3.     .findVariableDeclarators('foo') 
  4.     .renameTo('bar') 
  5.     .toSource(); 

jscodeshift 的優(yōu)勢是更簡潔。

但是 jscodeshift 能代替 babel 么?可以看下大牛給出的答案:

babel 和 jscodeshift 的不同

jscodeshift 的 parser 是 recast,曾經(jīng)有 babel 的維護者想結(jié)合這兩者:

https://github.com/facebook/jscodeshift/issues/168

利用 recast 做 parse,然后基于 babel parser 做轉(zhuǎn)換。

下面有一個很精彩的回復,明確了 babel 和 jscodeshift 的不同:

我來梳理一下:

babel 的 transform api 是visitor 風格,也就是聲明對什么 ast 做什么處理,然后在遍歷過程中被調(diào)用,這種不和具體遍歷方式耦合的寫法是一種設(shè)計模式(訪問者模式),處理再復雜的場景也能應(yīng)對。就是處理簡單場景顯得稍微啰嗦點。

jscodeshift 是 collection 風格,類似 jquery,主動查找 ast,放到集合中操作,適合處理簡單場景,要知道每種 ast 是怎么查找到的,然后做轉(zhuǎn)換,要處理很多很多 case,萬一查找路徑不對,那可能就漏掉了一些情況,比起 babel 來,很難在復雜場景下沒有 bug。

就像 jquery 和 mvvm 的區(qū)別一樣,復雜場景還是 mvvm 的方式(babel)靠譜,不會漏掉一些 dom 沒處理。(只是一個類比)

所以,簡單場景可以用 jscodeshift,而所有場景都可以用 babel。

babel 的 visitor 的優(yōu)點就是設(shè)計模式中訪問者模式的優(yōu)點,不和具體遍歷方式耦合易于復用。

為什么不推薦 gogocode

gogocode 是這兩天阿里媽媽出的 ast 修改工具,基于 babel 做了一層封裝,說是簡化了 ast 操作。

api 類似這樣:

 
 
 
 
  1. $(code) 
  2.   .find('var a = 1') 
  3.   .attr('declarations.0.id.name', 'c') 
  4.   .root() 
  5.   .generate(); 

沒錯,基于 babel 的 visitor 風格的 api 封裝出了 jscodeshift 的 collection 風格的 api。

本來 babel 的 visitor 雖然寫起來麻煩一些,但是所有路徑都能夠處理到,而改成 collection 風格之后,一旦落掉了某條路徑?jīng)]錯里,就會 bug。處理的 case 特別多,不適合復雜場景。

babel 本來的 visitor 模式是一種優(yōu)點,結(jié)果又在上層封裝出了 collection api。如果想這么封裝,為啥不直接基于 jscodeshift 呢。我沒看懂這波操作。

我不看好這個 babel 套娃,我沒有自信保證復雜場景下能夠處理所有路徑而不遺漏 case,復雜場景我選擇直接用 babel 的 api。

總結(jié)

babel 是訪問者設(shè)計模式的實現(xiàn),分離了遍歷方式和對 AST 的操作,使得操作可以復用,jscodeshift 是 collection 風格,類似 jquery,復雜場景容易落掉 case。

gogocode 基于babel 實現(xiàn)了 collection 風格,不看好,容易落下 case。

一句話總結(jié):簡單場景可以用 jscodeshift,所有場景都可以用 babel,不怎么推薦 gogocode。


文章名稱:為啥套娃?聊聊Babel、Jscodeshift和阿里媽媽的Gogocode
網(wǎng)頁路徑:http://www.5511xx.com/article/cojpjog.html