利用ESLint檢查程式碼質量
其實很早的時候就想嘗試ESLint了,但是很多次都是玩了一下就覺得這東西巨複雜,一執行檢查就是滿屏的
error
,簡直是不堪入目,遂放棄。直到某天終於下定決心深入看了文件,才發現其實挺簡單的,只是當時沒有看到合適入門教程而已。我相信很多人也有著跟我一樣的經歷,所以希望將自己的踩坑心得記錄下來,讓後來者更輕易地掌握ESLint的使用,因為它確實是個好東西。
JavaScript是一門神奇的動態語言,它在帶給我們程式設計的靈活性的同時也悄悄埋下了一些地雷。除了基本的語法錯誤能在程式一啟動的時候被檢測到之外,很多隱含的錯誤都是在執行的時候才突然地蹦出來。除非你的程式有著100%的測試覆蓋率,否則說不定哪天就會因為一個xxx
is undefined
ESLint是一個外掛化的javascript程式碼檢測工具,它可以用於檢查常見的JavaScript程式碼錯誤,也可以進行程式碼風格檢查,這樣我們就可以根據自己的喜好指定一套ESLint配置,然後應用到所編寫的專案上,從而實現輔助編碼規範的執行,有效控制專案程式碼的質量。
手把手入門
在開始使用ESLint之前,我們需要通過NPM來安裝它:
$ npm install -g eslint
我從Gist上找到了自己幾年前寫的一個小函式,將其儲存為檔案merge.js
:
function merge (){var ret ={};for(var i in arguments){var m = arguments[i];for(var j in m) ret[j]= m[j];}return ret;}
console.log(merge({a:123},{b:456}));
然後執行node merge.js
確保它是可以正確執行的(輸出結果為{
a: 123, b: 456 }
)。
接著我們執行以下命令來使用ESLint檢查:
$ eslint merge.js
可以看到,沒有任何輸出結果。這是因為我們沒有指定任何的配置,除非這個檔案是有語法錯誤,否則應該是不會有任何提示的。現在我們先使用內建的eslint:recommended
首先新建ESLint配置檔案.eslintrc.js
:
module.exports ={extends:'eslint:recommended',};
重新執行eslint merge.js
可以看到輸出了2個錯誤:
/example/merge.js
10:1 error Unexpected console statement no-console
10:1 error 'console'isnotdefinedno-undef✖2 problem (2 error,0 warnings)
這兩條提示資訊還是足夠我們搞清楚是怎麼回事的:
- Unexpected console statement no-console - 不能使用
console
- ‘console’ is not defined no-undef -
console
變數未定義,不能使用未定義的變數
針對第1條提示,我們可以禁用no-console
規則。將配置檔案.eslintrc.js
改為這樣:
module.exports ={extends:'eslint:recommended',
rules:{'no-console':'off',},};
說明:配置規則寫在rules
物件裡面,key
表示規則名稱,value
表示規則的配置,具體說明見下文。
重新執行檢查還是提示no-undef
:
/example/merge.js
10:1 error 'console'isnotdefinedno-undef✖1 problem (1 error,0 warnings)
這是因為JavaScript有很多種執行環境,比如常見的有瀏覽器和Node.js,另外還有很多軟體系統使用JavaScript作為其指令碼引擎,比如PostgreSQL就支援使用JavaScript來編寫儲存引擎,而這些執行環境可能並不存在console
這個物件。另外在瀏覽器環境下會有window
物件,而Node.js下沒有;在Node.js下會有process
物件,而瀏覽器環境下沒有。
所以在配置檔案中我們還需要指定程式的目標環境:
module.exports ={extends:'eslint:recommended',
env:{
node:true,},
rules:{'no-console':'off',},};
再重新執行檢查時,已經沒有任何提示輸出了,說明merge.js
已經完全通過了檢查。
配置檔案
ESLint還可以在專案的package.json
檔案中指定配置,直接將上文中的module.exports
的值寫到eslintConfig
裡面即可:
{"name":"my-package","version":"0.0.1","eslintConfig":{"extends":"eslint:recommended","env":{"node":true},"rules":{"no-console":"off"}}}
另外還可以在執行eslint
命令時通過命令列引數來指定,詳細文件可以參考這裡:Configuring
ESLint - 配置
規則
每條規則有3個等級:off
、warn
和error
。off
表示禁用這條規則,warn
表示僅給出警告,並不會導致檢查不通過,而error
則會導致檢查不通過。
有些規則還帶有可選的引數,比如comma-dangle
可以寫成[
"error", "always-multiline" ]
;no-multi-spaces
可以寫成[
"error", { exceptions: { "ImportDeclaration": true }}]
。
規則的詳細說明文件可以參考這裡:Rules - 規則
使用共享的配置檔案
上文我們以eslint:recommended
為基礎配置,然後在此之上修改no-console
這條規則。而在大多數時候,我們可能會根據自己個人或團隊的習慣,定製更多的規則,比如限定縮排是2個空格和使用單引號的字串等。而如果每一個專案都要這樣寫到.eslintrc.js
檔案上,管理起來會比較麻煩。
我們可以將定義好規則的.eslintrc.js
檔案儲存到一個公共的位置,比如public-eslintrc.js
:
module.exports ={extends:'eslint:recommended',
env:{
node:true,},
rules:{'no-console':'off','indent':['error',2],'quotes':['error','single'],},};
然後將原來的.eslintrc.js
檔案改成這樣:
module.exports ={extends:'./public-eslintrc.js',};
為了驗證這樣的修改是否生效,將merge.js
中的var
ret = {};
這一行前面多加一個空格,再執行ESLint檢查:
/example/merge.js
2:4 error Expected indentation of 2 space characters but found 3 indent
✖1 problem (1 error,0 warnings)
這時候提示的是縮排只能為2個空格,而檔案的第2行卻發現了3個空格,說明公共配置檔案public-eslintrc.js
已經生效了。
我們還可以使用已經發布到NPM上的ESLint配置,這些配置的模組名一般以eslint-config-
為字首,比如我在學習ESLint時自己編寫的一個配置名為eslint-config-lei
。要使用這個配置,先執行以下命令安裝它:
$ npm install -g eslint-config-lei
然後將.eslintrc.js
檔案改成這樣:
module.exports ={extends:'lei',};
再執行ESLint檢查,可以看到輸出如下的提示:
/example/merge.js
1:15 warning Unexpected space before function parentheses space-before-function-paren
2:3 error Unexpectedvar,use let orconst instead no-var3:8 error Unexpectedvar,use let orconst instead no-var4:5 error Unexpectedvar,use let orconst instead no-var5:10 error Unexpectedvar,use let orconst instead no-var10:19 warning A space is required after '{'object-curly-spacing
10:26 warning A space is required before '}'object-curly-spacing
10:29 warning A space is required after '{'object-curly-spacing
10:36 warning A space is required before '}'object-curly-spacing
✖9 problems (4 errors,5 warnings)
ESLint配置檔案中的extends
還可以用來指定各種來源的配置引用,具體說明可以參考以下連結:
程式碼格式化
在ESLint規則列表頁面,我們發現有些規則的旁邊會帶有一個橙色扳手圖示,表示在執行eslint
命令時指定--fix
引數可以自動修復該問題。
接著上文使用eslint-config-lei
配置的檢查,我們嘗試在執行檢查時新增--fix
引數:
$ eslint merge.js --fix
執行完畢,沒有發現任何提示。再開啟merge.js
檔案發現已經變成了這樣:
function merge(){const ret ={};for(const i in arguments){const m = arguments[i];for(const j in m) ret[j]= m[j];}return ret;}
console.log(merge({ a:123},{ b:456}));
主要的變化有以下三部分:
- 宣告函式時,函式名與引數列表的空格不見了:
merge ()
修改為merge()
var
宣告的變數變成了const
宣告:var ret = {}
修改為const ret = {}
- 物件的內容與花括號之間增加了空格:
{a: 123}
修改為{ a: 123 }
我們可以利用這個特性來自動格式化專案程式碼,這樣就可以保證程式碼書寫風格的統一。
釋出自己的配置
前文關於「共享的配置檔案」一小節已經提到,可以在extends
中指定一個檔名,或者一個eslint-config-
開頭的模組名。為了便於共享,一般推薦將其釋出成一個NPM模組。
其原理就是在載入模組時輸出原來.eslintrc.js
的資料。比如我們可以建立一個模組eslint-config-my
用於測試。
新建檔案eslint-config-my/index.js
:
module.exports ={extends:'eslint:recommended',
env:{
node:true,
es6:true,},
rules:{'no-console':'off','indent':['error',2],'quotes':['error','single'],},};
再新建檔案eslint-config-my/package.json
:
{"name":"eslint-config-my","version":"0.0.1","main":"index.js"}
為