1. 程式人生 > >利用ESLint檢查程式碼質量

利用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-undef2 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-undef1 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個等級:offwarnerroroff表示禁用這條規則,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"}