国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

深入對(duì)比 eslint 插件 和 babel 插件的異同點(diǎn)

開發(fā) 前端
babel 插件和 eslint 插件都能夠分析和轉(zhuǎn)換代碼,那這倆到底有啥不同呢?

 [[421277]]

babel 和 eslint 都是基于 AST 的,一個(gè)是做代碼的轉(zhuǎn)換,一個(gè)是做錯(cuò)誤檢查和修復(fù)。babel 插件和 eslint 插件都能夠分析和轉(zhuǎn)換代碼,那這倆到底有啥不同呢?

本文我們來探究下 babel 插件和 eslint 插件差別在哪里。

babel 插件

babel 的編譯流程分為 parse、transform、generate 3 步,可以指定插件,在遍歷 AST 的時(shí)候會(huì)合并調(diào)用 visitor。

比如我們寫一個(gè)在 console.xx 的參數(shù)插入文件名 + 行列號(hào)的插件:

對(duì)函數(shù)調(diào)用節(jié)點(diǎn)(CallExpression)的 callee 屬性進(jìn)行檢查,如果是 console.xx 的 api,則在 arguments 中插入一個(gè) StringLiteral 的字符串字面量節(jié)點(diǎn),值為文件名 + 行列號(hào)。

  1. const targetCalleeName = ['log''info''error''debug'].map(item => `console.${item}`); 
  2.  
  3. const parametersInsertPlugin = ({ types }, options) => { 
  4.     return { 
  5.         visitor: { 
  6.             CallExpression(path, state) { 
  7.                 const calleeName = path.get('callee').toString() 
  8.                 if (targetCalleeName.includes(calleeName)) { 
  9.                    const { line, column } = path.node.loc.start; 
  10.                    path.node.arguments.unshift(types.stringLiteral(`${options.file.filename}: (${line}, ${column})`)) 
  11.                } 
  12.             } 
  13.         } 
  14.     } 
  15. module.exports = parametersInsertPlugin; 

然后使用 babel core 的 api 進(jìn)行代碼編譯,并調(diào)用插件:

  1. const { transformFileSync } = require('@babel/core'); 
  2. const insertParametersPlugin = require('./plugin/parameters-insert-plugin'); 
  3. const path = require('path'); 
  4.  
  5. const inputFilePath = path.join(__dirname, './sourceCode.js'); 
  6.  
  7. const { code } = transformFileSync(inputFilePath, { 
  8.     plugins: [insertParametersPlugin], 
  9.     parserOpts: { 
  10.         sourceType: 'unambiguous'
  11.         plugins: ['jsx'
  12.     } 
  13. }); 
  14.  
  15. console.log(code); 

當(dāng)源碼為下面的代碼時(shí):

  1. console.log(1); 
  2.  
  3. function func() { 
  4.     console.info(2); 
  5.  
  6. export default class Clazz { 
  7.     say() { 
  8.         console.debug(3); 
  9.     } 
  10.     render() { 
  11.         return <div>{console.error(4)}</div> 
  12.     } 

目標(biāo)代碼為:

 

 

 

 

可以看到,在 console.xx 的 api 調(diào)用處插入了文件名和行列號(hào)的參數(shù)。

這就是一個(gè) babel 插件做代碼轉(zhuǎn)換的例子。

我們從中能總結(jié)出 babel 插件的特點(diǎn):

  • 插件的形式是函數(shù)返回一個(gè)對(duì)象,對(duì)象的 visitor 屬性聲明對(duì)什么節(jié)點(diǎn)做什么處理

  • visitor 函數(shù)可以通過 path 的 api 來對(duì) ast 增刪改

  • 修改后的 ast 會(huì)打印成目標(biāo)代碼

eslint 插件

eslint 插件也會(huì)對(duì)代碼進(jìn)行 parse,查找要檢查的 AST,之后進(jìn)行檢查和報(bào)錯(cuò),但不一定會(huì)修復(fù)代碼,只有指定了 fix 才會(huì)進(jìn)行修復(fù)。

我們寫一個(gè)檢查對(duì)象格式的 eslint 插件。

需求時(shí)把下面的代碼格式進(jìn)行檢查和修復(fù):

  1. const  obj = { 
  2.     a: 1,b: 2
  3.  
  4.     c: 3 

變成這種:

  1. const  obj = { 
  2.     a: 1
  3.     b: 2
  4.     c: 3 

eslint 是可以查找某個(gè) AST 關(guān)聯(lián)的 token 的,也就是我們可以拿到對(duì)象的每一個(gè)屬性開始和結(jié)束的 token 還有行列號(hào),

我們要校驗(yàn)上一個(gè)屬性結(jié)束的 token 的行號(hào)要等于下一個(gè)屬性開始的 token 的行號(hào)。

所以就是這樣寫:

指定對(duì) ObjectExpression 也就是 {} 表達(dá)式的每一個(gè)屬性的開始和結(jié)束 token 的行號(hào)做檢查,如果不是下一個(gè)屬性是上一個(gè)屬性的 +1 行,那就報(bào)錯(cuò)。

并且,還可以指定如何修復(fù),我們這里的錯(cuò)誤的修復(fù)方式就是把兩個(gè) token 之間的部分替換為換行符(os.EOL) + tab。

  1. const os = require('os'); 
  2.  
  3. module.exports = { 
  4.      meta: { 
  5.          fixable: true 
  6.      }, 
  7.      create(context) { 
  8.          const sourceCode = context.getSourceCode(); 
  9.          return { 
  10.             ObjectExpression(node) { 
  11.                 for (let i = 1; i < node.properties.length; i ++) { 
  12.                      const firstToken = sourceCode.getTokenAfter(node.properties[i - 1]); 
  13.                      const secondToken = sourceCode.getFirstToken(node.properties[i]); 
  14.                      if(firstToken.loc.start.line !== secondToken.loc.start.line - 1) { 
  15.                         context.report({ 
  16.                             node, 
  17.                             message: '對(duì)象屬性之間不能有空行'
  18.                             loc: firstToken.loc, 
  19.                             *fix(fixer) { 
  20.                                 yield fixer.replaceTextRange([firstToken.range[1],secondToken.range[0]], os.EOL + '\t'); 
  21.                             } 
  22.                         }); 
  23.                      } 
  24.                       
  25.                 } 
  26.              } 
  27.          }; 
  28.      } 
  29.  }; 

這樣就完成了對(duì)象格式的檢查和自動(dòng)修復(fù)。

這個(gè)插件文件名命名為 object-property-format,然后我們使用 api 的方式調(diào)用下:

首先,引入 eslint 模塊,創(chuàng)建 ESLint 對(duì)象:

  1. const { ESLint } = require("eslint"); 
  2.  
  3. const engine = new ESLint({ 
  4.     fix: false
  5.     overrideConfig: { 
  6.         parser: '@babel/eslint-parser'
  7.         parserOptions: { 
  8.             sourceType: "unambiguous"
  9.             requireConfigFile: false
  10.         }, 
  11.         rules: { 
  12.             "object-property-format""error" 
  13.         } 
  14.     }, 
  15.     rulePaths: ['./'], 
  16.     useEslintrc: false 
  17. }); 

這里把配置文件關(guān)掉(useEslintrc: false),只用這里的的配置(overrideConfig)。

我們指定用 babel 的 parser(@babel/eslint-parser),并且不需要 babel 配置文件。之后引入剛才我們寫的那個(gè) rule,也就是 object-property-format,報(bào)錯(cuò)級(jí)別設(shè)置為 error。

還需要指定 rulePaths,也就是告訴 eslint 去哪里查找 rule。

之后,我們調(diào)用 lintText 的 api 進(jìn)行 lint:

  1. (async function main() { 
  2.   const results = await engine.lintText(` 
  3.   const  obj = { 
  4.         a: 1,b: 2
  5.  
  6.         c: 3 
  7.     } 
  8.   `); 
  9.  
  10.   console.log(results[0].output); 
  11.  
  12.   const formatter = await engine.loadFormatter("stylish"); 
  13.   const resultText = formatter.format(results); 
  14.   console.log(resultText); 
  15. })() 

對(duì)于結(jié)果,我們使用內(nèi)置的 formater 格式化了一下。

用 node 執(zhí)行,結(jié)果如下:

 

 

 

 

可以看到,eslint 檢查出了對(duì)象格式的兩處錯(cuò)誤。

為什么沒有修復(fù)呢?因?yàn)闆]開啟 fix 啊,eslint 需要開啟 fix 才會(huì)修復(fù)代碼。

把 Eslint 的 fix option 修改為 true,再試一下:

 

 

 

 

可以看到,沒有報(bào)錯(cuò)了,而且代碼也進(jìn)行了修復(fù)。

這就是一個(gè) eslint 插件做代碼格式檢查和修復(fù)的例子。

我們從中總結(jié)出 eslint 插件的 rule 的特點(diǎn):

  • rule 的形式是對(duì)象,create 屬性是一個(gè)函數(shù),返回一個(gè)對(duì)象,指定對(duì)什么 AST 做什么檢查和修復(fù)

  • AST 處理函數(shù)可以通過 context 的 api 來拿到源碼不同位置的 token 來進(jìn)行格式的檢查

  • fix 函數(shù)可以拿到 fixer 的 api,來對(duì)某個(gè)位置的代碼進(jìn)行字符的增刪改

  • 默認(rèn)不會(huì)修復(fù)代碼,需要指定 fix 才會(huì)進(jìn)行修復(fù)

eslint 插件和 babel 插件的異同

我們把總結(jié)的 babel 插件和 eslint 插件的特點(diǎn)拿到一起對(duì)比下。(這里的 eslint 插件嚴(yán)格來說是指的 eslint 的 rule,eslint 插件可以包含多個(gè) rule。)

babel 插件:

  • 插件的形式是函數(shù)返回一個(gè)對(duì)象,對(duì)象的 visitor 屬性聲明對(duì)什么節(jié)點(diǎn)做什么處理

  • visitor 函數(shù)可以通過 path 的 api 來對(duì) ast 增刪改

  • 修改后的 ast 會(huì)打印成目標(biāo)代碼

eslint 插件:

  • rule 的形式是對(duì)象,create 屬性是一個(gè)函數(shù),返回一個(gè)對(duì)象,指定對(duì)什么 AST 做什么檢查和修復(fù)

  • AST 處理函數(shù)可以通過 context 的 api 來拿到源碼不同位置的 token 來進(jìn)行格式的檢查

  • fix 函數(shù)可以拿到 fixer 的 api,來對(duì)某個(gè)位置的代碼進(jìn)行字符的增刪改

  • 默認(rèn)不會(huì)修復(fù)代碼,需要指定 fix 才會(huì)進(jìn)行修復(fù)

我們來對(duì)比下兩者的異同:

  • 從形式上來說,eslint 的 rule 是對(duì)象-函數(shù)-對(duì)象的形式,而 babel 插件是函數(shù)-對(duì)象的形式,多的部分是 eslint rule 的元信息,也就是 meta 屬性。這是兩者設(shè)計(jì)上的不同。

  • babel 插件和 eslint rule 都可以遍歷節(jié)點(diǎn),指定對(duì)什么節(jié)點(diǎn)做處理,但是 babel 插件可以通過 path 的 api 來增刪改 AST,而 eslint 則是通過 context.getSourceCode() 拿到 sourceCode,然后通過 sourceCode 的 api 進(jìn)行格式的檢查,最后修復(fù)還要通過 fixer 的 api。

  • babel 插件的改動(dòng)默認(rèn)就是生效的,最多傳入 options 進(jìn)行控制,而 eslint 的 fix 功能只有開啟才生效。

eslint 的 AST 中記錄了在源碼中 range 信息,可以根據(jù) range 信息查找 token,但其實(shí) babel 也可以,babel parser 也可以指定 ranges、tokens

 

 

 

 

也就是說理論上基于 babel 完全可以實(shí)現(xiàn) eslint 的功能,只不過兩者 api 設(shè)計(jì)上的不同,導(dǎo)致了兩者適合的場(chǎng)景不同。

  • babel 是通過 path api 進(jìn)行 AST 增刪改,適合做代碼分析和轉(zhuǎn)換。

  • eslint 是通過 sourceCode 和 fixer api 進(jìn)行代碼格式的檢查和 fix,適合做錯(cuò)誤檢查和修復(fù)。

但是,從本質(zhì)上來說,兩者編譯流程上差別并不大。

總結(jié)

我們寫了一個(gè)在 console.xx api 插入?yún)?shù)的 babel 插件,又寫了一個(gè)檢查和修復(fù)對(duì)象格式的 eslint 插件,分析了兩者的特點(diǎn),然后做了下對(duì)比。

兩者插件形式上不同,api 也不同:

babel 是通過 path 的 api 對(duì) AST 進(jìn)行增刪改,而 eslint 是通過 sourceCode 的 api 進(jìn)行代碼格式的檢查,通過 fixer 的 api 進(jìn)行修復(fù)。這就導(dǎo)致了 babel 插件更適合做代碼轉(zhuǎn)換,eslint 插件更適合做代碼格式的校驗(yàn)和修復(fù)。但實(shí)際上 babel 也能做到 eslint 一樣的事情,兩者本質(zhì)上的編譯流程是差不多的。

這篇文章把 babel 插件和 eslint 插件放到一起進(jìn)行了對(duì)比,講述了兩者本質(zhì)的相同和 api 的不同,希望能夠幫大家更好的掌握 babel 和 eslint 插件。

 

責(zé)任編輯:張燕妮 來源: 神光的編程秘籍
相關(guān)推薦

2021-09-02 13:38:48

Eslint Babel 插件

2021-11-19 23:54:19

插件Eslint

2009-11-06 10:11:34

WCF和Web Ser

2015-05-22 09:49:25

2009-12-18 15:23:03

Vista和XP路由設(shè)

2021-10-13 22:19:16

插件Babel import

2012-12-07 10:56:32

2010-06-13 09:18:28

UML依賴

2021-09-11 19:46:14

配置

2009-12-29 15:56:57

2022-01-18 18:46:55

Eslint抽象語法樹Babel

2022-07-18 14:18:26

Babel代碼面試

2022-09-30 15:46:26

Babel編譯器插件

2012-11-22 13:02:24

jQuery插件Web

2009-11-10 11:25:35

VB.NET與Basi

2021-06-22 06:52:46

Vite 插件機(jī)制Rollup

2009-12-11 10:29:03

PHP插件機(jī)制

2010-08-11 16:37:47

DB2數(shù)據(jù)庫(kù)

2021-09-05 11:37:31

Eslint插件Vue

2009-11-11 13:59:15

ADO.NET與ADO
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

97在线视频国产| 亚洲精品短视频| 视频免费裸体网站| 欧美日一区二区| 亚洲精品日日夜夜| 亚洲欧美日韩天堂一区二区| 超碰个人在线| 欧美精品日韩精品| 黄色网址视频在线观看| 欧美激情网站| 国产精品久久..4399| 精品亚洲porn| www污在线观看| 国产**成人网毛片九色| 高清无码视频直接看| 国产福利91精品一区| 欧美亚洲黄色片| www成人在线观看| 国产wwwxx| 亚洲电影一区二区| 青春草在线观看 | 成人资源av| 一区二区视频欧美| 欧美影视一区二区| 国产乱一区二区| 99蜜桃臀久久久欧美精品网站| 国产三级精品视频| 中文字幕中文字幕在线中文字幕三区| 欧美色图12p| 韩国女主播一区二区| 91精品国产色综合久久不卡98口| 国产探花一区| 欧美aaaaa喷水| 成人免费观看av| 黄色高清在线观看| 精品三级在线观看| 亚洲精品国产九九九| 国产日韩av在线| 麻豆视频一区二区| 国产原创精品在线| 7777精品伊人久久久大香线蕉 | 欧美成人r级一区二区三区| 天天综合网天天| 91av在线影院| 精品亚洲美女网站| 丁香在线视频| 成人免费午夜电影| 国产一区二区精品丝袜| 99精品美女视频在线观看热舞| 欧美激情视频给我| 激情视频一区二区三区| 欧美人成在线观看| 午夜视频一区在线观看| 狠狠操一区二区三区| 2019亚洲日韩新视频| 一区二区日本视频| 超碰在线97免费| 欧美日本韩国一区二区三区视频| 久久青草免费| 国产69精品久久久久9999apgf| porn视频在线观看| 另类av导航| 69精品小视频| 成人在线高清免费| 欧美中文字幕在线播放| √天堂资源地址在线官网| 中文字幕国内自拍| 亚洲综合一区二区| 午夜精品偷拍| 国内av免费| 91国产中文字幕| 国产精品久久久久久久久久久免费看 | 青青草91久久久久久久久| 久久久综合香蕉尹人综合网| 91蜜桃婷婷狠狠久久综合9色| 国产高清在线看| 久久99精品久久久久久青青91| 最新国产拍偷乱拍精品| 国产日韩欧美久久| 亚洲乱码国产乱码精品精| 91成人免费| 成人一级片网站| 日韩精品在线免费观看| 91久久视频| 中文字幕在线第一页| 欧美精品一区二区免费| 国产主播一区二区| 日本视频在线播放| 国产精品日韩欧美| 国产视频亚洲色图| 中文字幕一区二区三区乱码在线 | 香蕉视频在线播放| 成人毛片视频网站| 亚洲黄色小说网站| 亚洲调教一区| 国产av熟女一区二区三区| 久久99精品久久久久久琪琪| 欧美性做爰毛片| youjizzjizz亚洲| 欧美xxxx做受欧美护士| av片在线观看| 亚洲 日韩 国产第一区| 一本久久精品一区二区| 成人一区二区| 亚洲第一成年免费网站| 成人性爱视频在线观看| 精品久久久久久久久久中文字幕| 亚洲mv在线看| 怡红院在线观看| 91av久久| 天堂av在线免费观看| 黄色在线观看网| 久久6免费高清热精品| 毛片av一区二区| 求av网址在线观看| 2022国产精品| 天天色天天爱天天射综合| 国产极品模特精品一二| 国产一级片黄色| 欧美高清激情视频| 欧美激情一区二区| 日韩高清在线观看一区二区| 日韩在线综合网| 久久大大胆人体| 国产三级精品三级| 美女视频免费精品| 色偷偷免费视频| 国产精品视频1区| 欧美性xxxx在线播放| 亚洲久久久久| 高清毛片在线看| 精品欧美日韩| 日韩精品一区二区三区三区免费| 久久精品30| av在线小说| 99在线免费视频观看| 欧美激情精品久久久久| 亚洲精品一二三| 第一会所亚洲原创| 撸视在线观看免费视频| 国产中文一区二区| 亚洲国产一区自拍| 91小视频在线观看| 狼人精品一区二区三区在线 | 国产一区二区导航在线播放| 91黄页在线观看| 亚洲 欧美 综合 另类 中字| 久久九九亚洲综合| 中文字幕av资源一区| 精品久久久久久久久久久下田| 中文字幕亚洲精品视频| 精品麻豆av| 综合国产在线观看| 亚洲同性gay激情无套| 国产精品99一区二区| 久热在线观看视频| 日韩精品你懂的| 91久久国产精品| 亚洲精品国产拍免费91在线| 国产午夜亚洲精品理论片色戒| 日韩成人三级| av资源中文在线| 伊人影院综合在线| 精品国产91亚洲一区二区三区www| 亚洲免费中文字幕| 亚洲愉拍自拍另类高清精品| 久久高清一区| 玖玖精品一区| 国产视频第一区| www.xxx麻豆| 国产精品网址在线| 亚洲福利在线观看| 亚洲欧美一区二区三区极速播放| 亚洲深爱激情| 国产亚洲字幕| 91精品专区| 欧美老熟妇喷水| 99精品国产一区二区| 亚洲社区在线观看| 一区二区三区 在线观看视频| av不卡在线| 亚洲免费看片| 福利视频在线导航| 亚洲人成无码网站久久99热国产 | 亚洲a级在线观看| 日韩精品免费电影| 亚洲影院久久精品| 国产高清精品网站| 成人影院在线| 欧美xxxx网站| 91官网在线| 三级短视频在线| 欧美成人直播| 色综合久久网女同蕾丝边| 中文字幕一区二区三区四区五区人 | 超碰在线免费观看97| 91精品久久久久久久久久| 国产一区二区动漫| 欧美精品一级二级三级| 亚洲精品久久久久久国产精华液|