一、為什么要用ESLint
1、總結為兩點:保持代碼風格一致、減少代碼出錯幾率
為了解決這類靜態代碼問題,每個團隊都需要一個統一的 JS 代碼規范,團隊成員都遵守這份代碼規范來編寫代碼。當然,靠人來保障代碼規范是不可靠的,需要有對應的工具來保障,ESLint 就是這個工具
2、為什么不是Prettier
Prettier確實可以按照設置的規則對代碼進行統一格式化,但是需要明確的一點是,Prettier只會在格式上對代碼進行格式化,一些隱藏的代碼質量問題Prettier是無法發現的,而ESLint可以。
3、目標:開發時提示、保存時自動修復、提交時檢測
二、ESlint 演進歷史
提到ESLint,我們就不得不提及他的前輩們JSLint和JSHint,以及它們的區別。
1、JSLint:
JSLint 的靈感來源於C語言的檢查工具 Lint,用來掃描C語言源文件以便找到其中的錯誤。
JSlint 是在2010年開源的第一款針對JS的語法檢測工具,它和Lint做着相同的事,掃描JS的源文件來找到錯誤;它內部也是通過fs.readFile來讀取文件然后逐行來進行檢查
JSLint的問題很明顯:所有的配置項都內置不可配置,本身推崇愛用不用的傳統,不像開發者開放配置或者修改他覺得對的規則,因此很多人也無法忍受他的規則
2、JSHint,它的初衷就是為了能讓開發者自定義規則 lint rules,因此提供了豐富的配置項,給開發者極大的自由
JSHint相比於JSLint,最大的特點就是可配置,我們可以在項目中放入一個.jshintrc的配置文件,JSLint就會加載配置文件用於代碼分析
由於JSHint是基於JSLint開發的,因此JSLint的一些問題也繼承下來了,比如不易擴展以及不容易直接根據報錯定位到具體的配置規則等
3、ESLint
2013年 Zakas 大佬發現JSHint無法滿足自己定制化規則的需要,因此設想開發一個基於AST的Linter,可以動態執行額外的規則,同時可以很方面的擴展規則,於是在13年6月份開源推出了全新的ESLint。
靈感來源於PHP Linter,將源碼解析成AST,然后檢測AST是否符合規則;ESLint最開始使用esprima解析器將源碼解析成AST,然后就可以使用任意規則來檢測AST是否符合預期,這也是ESLint高可擴展的原因。
剛開始ESlint的推出並沒有撼動JSHint的霸主地位,由於ESlint需要將源碼轉為AST,而JSHint直接檢測源文件字符串,因此執行速度比JSHint慢很多;真正讓ESLint實現彎道超車的是ES6的出現
2015年,ES6規范發布后,由於大部分瀏覽器支持程度不高,因此需要Babel將代碼轉換編譯成ES5或者更低版本;同時由於ES6變化很大,短期內JSHint無法完全支持,這時ESLint的高擴展性的優點顯現出來了,不僅可以擴展規則,連默認的解析器也能替換;Babel團隊就為ESLint開發了babel-eslint替換默認的解析器esprima,讓ESLint率先支持ES6。
三、ESLint 配置
ESLint被設計成完全可配置的,我們可以用多種方式配置它的規則,或者配置要檢測文件的范圍。
1、初始化:如果想在現有的項目中引入eslint,我們可以在項目中進行初始化:
npm i eslint --save-dev npx eslint --init
在經過一系列問答后,會在項目根目錄創建一個我們熟悉的.eslintrc.js配置文件;安裝后就可以通過命令行對項目中的文件需要檢測了:
# 檢測單個文件
npx eslint file1.js file2.js
# 檢測src和scripts目錄
npx eslint src scripts
一般我們會把eslint命令行配置到packages.json中:
"scripts": { "lint": "npx eslint src scripts", "lint:fix": "npx eslint src scripts --fix", "lint:create": "npx eslint --init" }
這里有一個--fix后綴,是ESLint提供自動修復基礎錯誤的功能,我們運行lint:fix后發現有一些報錯信息消失了,代碼也改變了;不過它只能修復一些基礎的不影響代碼邏輯的錯誤,比如代碼末尾加上分號、表達式的空格等等。
ESLint默認只會檢測.js后綴的文件,如果我們想對更多類型的文件進行檢測,比如.vue、.jsx,可以使用--ext選項,參數用逗號分隔:
"scripts": { "lint": "npx eslint --ext .js,.jsx,.vue src", }
對於一些公共的js,或者測試腳本,不需要進行檢測,我們可以通過在項目根目錄創建一個.eslintignore告訴ESLint去忽略特定的目錄或者文件:
public/ src/main.js
除了.eslintignore中指定的文件或目錄,ESLint總是忽略/node_modules/* 和/bower_components/*中的文件;因此對於一些目前解決不了的規則報錯,但是我們需要打包上線,在不影響運行的情況下,我們就可以利用.eslintignore文件將其暫時忽略。
2、ESLint一共有兩種配置方式
- 配置注釋:使用JavaScript注釋把配置信息直接嵌入到一個代碼源文件中
- 配置文件:1. 使用 JavaScript、JSON 或者 YAML 文件為整個目錄(處理你的主目錄)和它的子目錄指定配置信息。可以配置一個獨立的
.eslintrc.*文件,或者直接在package.json文件里的eslintConfig字段指定配置,ESLint 會查找和自動讀取它們,再者,你可以在命令行運行時指定一個任意的配置文件。
(1)第一種方式是直接把lint規則嵌入源代碼中;
/* eslint eqeqeq: "error" */
var num = 1 num == '1'
eqeqeq代表eslint校驗規則,error代表校驗報錯級別,后面會詳細說明;這個eslint校驗規則只會對該文件生效
我們還可以使用其他注釋,更精確地管理eslint對某個文件或某一行代碼的校驗:
/* eslint-disable */ alert('該注釋放在文件頂部,eslint不會檢查整個文件') /* eslint-enable */ alert('重新啟用eslint檢查') /* eslint-disable eqeqeq */ alert('只禁止某一個或多個規則') /* eslint-disable-next-line */ alert('下一行禁止eslint檢查') alert('當前行禁止eslint檢查') // eslint-disable-line
(2)第二種方式是直接把lint規則放到我們的配置文件中,
上面init初始化生成的.eslintrc.js就是一個配置文件,官方還提供了其他幾種配置文件名稱(優先級從上到下),一般情況下我們使用.eslintrc.js就可以了。
.eslintrc.js
.eslintrc.yaml
.eslintrc.yml
.eslintrc.json
.eslintrc
package.json
四、配置詳解
// 我們詳細看下.eslintrc.js文件內部有哪些配置選項:
module.exports = { "globals": {}, "env": { "browser": true, "es2021": true }, "extends": "eslint:recommended", "parse": "babel-eslint", "parserOptions": { "ecmaVersion": 12, "sourceType": "module" }, "rules": {} };
1、globals 全局變量:腳本在執行期間訪問的額外的全局變量
當訪問當前源文件內未定義的變量時,no-undef 規則將發出警告。如果你想在一個源文件里使用全局變量,在Globals中定義這些全局變量,這樣ESLint就不會發出警告了
首先是我們的 globals ,ESLint會檢測未聲明的變量,並發出報錯,比如node環境中的process,瀏覽器環境下的全局變量console,以及我們通過cdn引入的jQuery定義的$等;我們可以在 globals 中進行變量聲明:
{ "globals": { // true表示該變量可讀寫,false表示變量是只讀
"$": true, "console": false } }
2、env 環境
但是node或者瀏覽器中的全局變量很多,如果我們一個個進行聲明顯得繁瑣,因此就需要用到我們的 env,這是對環境定義的一組全局變量的預設:一個環境定義了一組預定義的全局變量
指定不同的環境可以給對應環境下提供預設的全局變量,比如說在 browser 環境下,可以使用 window 全局變量;在 node 環境下,可以使用 process 全局變量等。
這些環境並不是互斥的,所以可以同時定義多個。可以在源文件里、在配置文件中或使用 命令行 的
--env選項來指定環境。
{ "env": { "browser": true, "node": true, "jquery": true } }
更多的環境參數可以看ESLint聲明環境。
3、parser解析器及解析參數parserOptions
這里可以類比webpack,自身只能處理js、及json文件,css、html等文件需要通過自定義loader處理來理解
解析器將源代碼轉換為稱為抽象語法樹AST的數據格式,然后,插件使用這種數據格式圍繞代碼的外觀或行為創建稱為lint規則的斷言。
我們上面說到ESLint可以更換解析器,"parse": "babel-eslint"就是用來指定要使用的解析器,它有以下幾個選擇:
- esprima:ESLint最開始使用的解析器
- espree:默認,ESLint自己基於esprima v1.2.2開發的一個解析器
- babel-eslint:一個對Babel解析器的包裝,使其能夠與ESLint兼容。
- @typescript-eslint/parser:將TypeScript轉換成與estree兼容的形式,以便在ESLint中使用。
那么這幾個解析器怎么選擇呢?如果你想使用一些先進的語法(ES6789),就使用babel-eslint(需要npm安裝);如果你想使用typescript,就使用@typescript-eslint/parser。
選好了解析器,我們可以通過parserOptions給解析器傳入一些其他的配置參數:
{ "parser": "babel-eslint", "parserOptions": { // 代碼模塊類型,可選script(默認),module
"sourceType": "module", // es版本號,默認為5,可以使用年份2015(同6)
"ecamVersion": 6, // es 特性配置
"ecmaFeatures": { "globalReturn": true, // 允許在全局作用域下使用 return 語句
"impliedStrict": true, // 啟用全局 strict mode
"jsx": true // 啟用 JSX
} }, }
4、規則 rules
ESLint可以配置大量的規則,我們可以在配置文件的rules屬性自定義需要的規則:
對於檢驗規則,有3個報錯等級:
- "off" 或 0:關閉規則
- "warn" 或 1:開啟規則,warn級別的錯誤 (不會導致程序退出)
- "error" 或 2:開啟規則,error級別的錯誤(當被觸發的時候,程序會退出)
有些規則沒有屬性,只需控制開啟還是關閉;有些規則可以傳入屬性,我們通過數組的方式傳入參數:
{ "rules":{ // 代碼縮進,使用tab縮進,switch語句的case縮進級別,1表示2個空格
"indent": ["error", "tab", { "SwitchCase": 1 }], // 引號,雙引號
"quotes": ["error", "double"], // 在語句末尾使用分號
"semi": ["error", "always"] } }
對於剛接觸ESLint的同學,看到這么多的規則肯定很懵逼,難道要一條一條來記么?肯定不是的;項目的ESLint配置文件並不是一次性完成的,而是在項目開發中慢慢完善起來的,因為並不是所有的規則都是我們項目所需要的。因此我們可以先進行編碼,在編碼的過程中使用npm run lint校驗代碼規范,如果報錯,可以通過報錯信息去詳細查看是那一條規范報錯:

比如這里的報錯no-unused-vars我們可以看到它來自第六行,再去文檔查找,發現是我們在js中有一個定義了卻未使用的變量;在團隊協商后可以進一步來確定項目是否需要這條規范。
5、擴展 extends
如果每條規則都需要團隊協商配置還是比較繁瑣的,在項目開始配置時,我們可以先使用一些業內已經成熟的、大家普遍遵循的編碼規范(最佳實踐);我們可以通過extends字段傳入一些規范,它接收String/Array:
{ "extends": [ "eslint:recommended", "plugin:vue/essential", "@vue/prettier", "eslint-config-standard" ] }
extends可以使用以下幾種類型的擴展:
- eslint:開頭的ESLint官方擴展,有兩個:
eslint:recommended(推薦規范)和eslint:all(所有規范)。 - plugin:開頭的擴展是插件類型擴展
- eslint-config:開頭的來自npm包,使用時可以省略
eslint-config-,比如上面的可以直接寫成standard - @:開頭的擴展和eslint-config一樣,是在npm包上面加了一層作用域scope
需要注意的是:多個擴展中有相同的規則,以后面引入的擴展中規則為准。
eslint:recommended推薦使用的規則在規則列表的右側用綠色√標記。

插件類型的擴展一般先通過npm安裝插件,以上面的vue為例,我們先來安裝:npm install --save-dev eslint eslint-plugin-vue
安裝后一個插件中會有很多同類型擴展可供選擇,比如vue就有以下幾種擴展:
- plugin:vue/base:基礎
- plugin:vue/essential:必不可少的
- plugin:vue/recommended:推薦的
- plugin:vue/strongly-recommended:強烈推薦
針對擴展中的規則,我們也能夠通過rules來對它進行覆寫
{ "extends": [ "plugin:vue/recommended" ], "rules": { // 覆寫規則
"vue/no-unused-vars": "error" } }
除了上面的eslint-config-standard,還有以下幾個比較知名的編碼規范:

不過需要注意的是,很多規范不僅需要安裝擴展本身,還需要配合插件,比如eslint-config-standard,我們還需要安裝下面幾個插件才能有效:
npm i eslint-config-standard -D npm i eslint-plugin-promise eslint-plugin-import eslint-plugin-node -D
6、插件 plugins
ESLint雖然可以定義很多的rules,以及通過extends來引入更多的規則,但是說到底只是檢查JS語法。如果需要檢查Vue中的template或者React中的jsx,就束手無策了。所以引入插件的目的就是為了增強ESLint的檢查能力和范圍。在配置文件里配置插件時,可以使用
plugins關鍵字來存放插件名字的列表。插件名稱可以省略eslint-plugin-前綴。
在Webpack中,插件是用來擴展功能,讓其能夠處理更多的文件類型以及功能,ESLint中的插件也是同樣的作用;雖然ESLint提供了幾百種規則可供選擇,但是隨着JS框架和語法的發展,這么多規則還是顯得不夠,因為官方的規則只能檢查標准的JS語法;如果我們寫的是vue或者react的jsx,那么ESLint就不能檢測了。
這時就需要安裝ESLint插件,用來定制一些特色的規則進行檢測;eslint插件以eslint-plugin-開頭,使用時可以省略;比如我們上面檢測.vue文件就用到eslint-plugin-vue插件;需要注意的是,我們在配置eslint-plugin-vue這個插件時,如果僅配置"plugins": ["vue"],vue文件中template內容還是會解析失敗。
這是因為不管是默認的espree還是babel-eslint解析器都無法解析.vue中template的內容;eslint-plugin-vue插件依賴vue-eslint-parser解析器,而vue-eslint-parser解析器只會解析template內容,不會檢測script中的JS內容,因此我們還需要指定一下解析器:
{ "extends": ["eslint:recommended"], "plugins": ["vue"], "parser": "vue-eslint-parser", "parserOptions": { "parser": "babel-eslint", "ecmaVersion": 12, "sourceType": "module", }, }
上面parserOptions.parser不少同學肯定看的有點迷糊,這是由於外層的解析器只能有一個,我們已經用了vue-eslint-parser就不能再寫其他的;因此vue-eslint-parser的做法是在解析器選項中再傳入一個解析器選項用來處理script中的JS內容。
如果想讓ESLint檢測vue文件,確保將.vue后綴加入--ext選項中。
// 而react配置則較為簡單了,引入插件,選擇對應的擴展規則即可:
{ "extends": [ "eslint:recommended", "plugin:react/recommended" ], "parserOptions": { // 啟用jsx語法支持
"ecmaFeatures": { "jsx": true }, "ecmaVersion": 12, "sourceType": "module" }, "plugins": [ "react" ], }
7、其他配置:配置當前目錄為 root
ESLint檢測配置文件步驟:
- 在要檢測的文件同一目錄里尋找
.eslintrc.*和package.json; - 緊接着在父級目錄里尋找,一直到文件系統的根目錄;
- 如果在前兩步發現有
root:true的配置,停止在父級目錄中尋找.eslintrc; - 如果以上步驟都沒有找到,則回退到用戶主目錄
~/.eslintrc中自定義的默認配置;
{ "root": true, }
五、ESLint 校驗文件
// 校驗 a.js 和 b.js
npx eslint a.js b.js // 校驗 src 和 scripts 目錄
npx eslint src scripts
2、校驗其他類型文件
通常ESLint只能校驗JS文件。比如需要校驗.vue文件,光配置vue插件和vue-eslint-parser解析器是不夠的,還需要讓ESLint在查找文件的時候找到.vue文件。ESLint提供了--ext來指定具體需要校驗的文件
npx eslint --ext .js,.vue src
3、自動修復部分校驗錯誤的代碼
rules列表項 中標識了🔧規則表示該規則是可以自動修復的,ESLint提供了--fix

// package.json配置scripts
{ "scripts": { "lint": "npx eslint --ext .js,.vue src", "lint:fix": "npx eslint --fix --ext .js,.vue src", } }
4、過濾一些不需要校驗的文件:通過創建一個.eslintignore文件來配置,告訴 ESLint 校驗的時候忽略它們
學習鏈接:https://mp.weixin.qq.com/s/Gg37sEBsu3J5Ov6a8Frq5w
