ESLint 是一個應用廣泛的 JavaScript 程式碼檢查工具。本文主要介紹由 AlloyTeam 總結的 ESLint 配置,以及應用 ESLint 配置時的一些經驗和工具。
配置原則
我們依據以下三條原則,研讀了 ESLint 所有的配置項,定製出了心目中「完美」的 ESLint 配置。
- 能夠幫助發現程式碼錯誤的規則,全部開啟
- 配置不應該依賴於某個具體專案,而應儘可能的合理
- 幫助保持團隊的程式碼風格統一,而不是限制開發體驗
配置解讀
我們對每一條配置,都有詳盡的註釋,這樣不僅方便了我們自己查閱某項配置的意義和如此配置的原因,也使大家更容易配置出自己心目中的規則:
- 每一條配置都有註釋說明此配置的用途
- 對於理解困難的配置,都在註釋中有舉例
- 對於有爭議的配置,都在註釋中說明了為什麼要這麼配置的原因
- 對於關閉掉的配置,都在註釋中有對應的原因說明,以及
@off
的標識 - 對於能夠 autofix 的配置,都在註釋中有標註
@autofix
詳細的配置內容在這裡:
下面列出一個程式碼片段供參考:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
module.exports = { parser: 'babel-eslint', parserOptions: { ecmaVersion: 2017, sourceType: 'module', ecmaFeatures: { experimentalObjectRestSpread: true, jsx: true } }, env: { browser: true, node: true, commonjs: true, es6: true }, // 以當前目錄為根目錄,不再向上查詢 .eslintrc.js root: true, rules: { // // // 可能的錯誤 // 這些規則與 JavaScript 程式碼中可能的語法錯誤或邏輯錯誤有關 // // 禁止 for 迴圈出現方向錯誤的迴圈,比如 for (i = 0; i < 10; i--) 'for-direction': 'error', // getter 必須有返回值,並且禁止返回空,比如 return; 'getter-return': [ 'error', { allowImplicit: false } ], // 禁止將 await 寫在迴圈裡,因為這樣就無法同時傳送多個非同步請求了 // @off 要求太嚴格了,有時需要在迴圈中寫 await 'no-await-in-loop': 'off', // 禁止與負零進行比較 'no-compare-neg-zero': 'error', // 禁止在 if, for, while 裡使用賦值語句,除非這個賦值語句被括號包起來了 'no-cond-assign': [ 'error', 'except-parens' ], // 禁止使用 console // @off console 的使用很常見 'no-console': 'off', // 禁止將常量作為 if, for, while 裡的測試條件,比如 if (true), for (;;),除非迴圈內部有 break 語句 'no-constant-condition': [ 'error', { checkLoops: false } ], // 禁止在正規表示式中出現 Ctrl 鍵的 ASCII 表示,即禁止使用 /\x1f/ // 開啟此規則,因為字串中一般不會出現 Ctrl 鍵,所以一旦出現了,可能是一個程式碼錯誤 'no-control-regex': 'error', // @fixable 禁止使用 debugger 'no-debugger': 'error', // 禁止在函式引數中出現重複名稱的引數 'no-dupe-args': 'error', // 禁止在物件字面量中出現重複名稱的鍵名 'no-dupe-keys': 'error', } }; |
使用方法
標準規則
安裝
1 |
npm install --save-dev eslint-config-alloy babel-eslint |
配置 .eslintrc.js
在你的專案根目錄下建立 .eslintrc.js
,並將以下內容複製到檔案中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
module.exports = { extends: [ 'eslint-config-alloy', ], globals: { // 這裡填入你的專案需要的全域性變數 // 這裡值為 false 表示這個全域性變數不允許被重新賦值,比如: // // jQuery: false, // $: false }, rules: { // 這裡填入你的專案需要的個性化配置,比如: // // // @fixable 一個縮排必須用兩個空格替代 // 'indent': [ // 'error', // 2, // { // SwitchCase: 1, // flatTernaryExpressions: true // } // ] } }; |
React 版
安裝
1 |
npm install --save-dev eslint-config-alloy eslint-plugin-react babel-eslint |
配置 .eslintrc.js
在你的專案根目錄下建立 .eslintrc.js
,並將以下內容複製到檔案中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
module.exports = { extends: [ 'eslint-config-alloy/react', ], globals: { // 這裡填入你的專案需要的全域性變數 // 這裡值為 false 表示這個全域性變數不允許被重新賦值,比如: // // React: false, // ReactDOM: false }, rules: { // 這裡填入你的專案需要的個性化配置,比如: // // // @fixable 一個縮排必須用兩個空格替代 // 'indent': [ // 'error', // 2, // { // SwitchCase: 1, // flatTernaryExpressions: true // } // ], // // @fixable jsx 的 children 縮排必須為兩個空格 // 'react/jsx-indent': [ // 'error', // 2 // ], // // @fixable jsx 的 props 縮排必須為兩個空格 // 'react/jsx-indent-props': [ // 'error', // 2 // ] } }; |
Vue 版
安裝
1 |
npm install --save-dev eslint-config-alloy eslint-plugin-vue babel-eslint |
配置 .eslintrc.js
在你的專案根目錄下建立 .eslintrc.js
,並將以下內容複製到檔案中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
module.exports = { extends: [ 'eslint-config-alloy/vue', ], globals: { // 這裡填入你的專案需要的全域性變數 // 這裡值為 false 表示這個全域性變數不允許被重新賦值,比如: // // Vue: false }, rules: { // 這裡填入你的專案需要的個性化配置,比如: // // // @fixable 一個縮排必須用兩個空格替代 // 'indent': [ // 'error', // 2, // { // SwitchCase: 1, // flatTernaryExpressions: true // } // ] } }; |
程式碼改造經驗
如果是一個新專案,應用一個比較嚴格的 ESLint 規則並不是一件難事。
但是如果是一個已經維護多年的老專案,那麼突然引入 ESLint 就會有成千上萬個錯誤。這個時候該如何改造呢?
1. 將所有報錯的配置都關閉
執行 ESLint 之後,會有很多錯誤,這時候我們可以把他們先暫時關閉掉。
由於專案還在不停地迭代,這樣可以保證其他不會報錯的規則能夠應用到新增的檔案上。
這時你的 .eslintrc.js
應該類似與下面的樣子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
module.exports = { extends: [ '@alloyteam/eslint-config-standard', ], globals: { React: false, jQuery: false, $: false }, rules: { 'no-dupe-keys': 'off', 'no-var': 'off', 'complexity': 'off', 'indent': 'off' } }; |
小技巧:如果報錯的規則太多了,可以在執行 ESLint 的時候,加上引數 -f json
,這樣的話會以 json 格式輸出,然後稍作處理就可以直接得到所有報錯的規則了。
注意:一開始不要開啟 --fix
,因為修復的太多了,就難以 review 程式碼了。
2. 針對每個配置,修復所有報錯的檔案,優先修復能夠 autofix 的配置
將 .eslintrc.js
中的 rules 刪掉一行,然後重新執行 ESLint 檢查。
- 如果可以 autofix,則加上
--fix
即可 - 如果不能 autofix,則需要一個檔案一個檔案的手動修改
建議優先修復能夠 autofix 的配置。
在這一步中,我們一次只修復一個 ESLint 配置,這樣的好處是 code review 的時候,目的很明確,不會出現問題。
小技巧:如果一個配置不能 autofix,又有很多檔案報錯,那麼可以嘗試寫一些指令碼去處理,利用 ESLint 中的引數 -f json
,可以解析到所有報錯的檔案和報錯的行數。
小技巧:如果寫指令碼也難以處理,那麼可以用編輯器的巨集功能快速的執行重複的操作,對於 VSCode,可以使用這個工具: https://github.com/geddski/macros
注意:不要陷於某一個配置的泥潭,優先解決容易修復的問題。
3. 針對難以修復的配置,將報錯的檔案忽略掉對應的規則,將來再慢慢修復
有時一個配置需要理解業務邏輯,讀懂上下文,很難去修復。
這個時候,可以在報錯的檔案頭部加上 ESLint 註釋,忽略掉對應的規則,將來只要搜尋對應的 ESLint 註釋就可以一個檔案一個檔案的修復問題了。
比如 eqeqeq
限制必須使用 ===
而不是 ==
,程式碼中使用了 if (result == '2')
,然而我們並不知道 ajax 返回的資料是 number 還是 string。這時候就可以在對應的檔案頭部加上:
1 |
/* eslint eqeqeq:0 */ |
這樣就可以針對這個檔案關閉掉 eqeqeq 這個規則了。
相比於將規則在 .eslintrc.js
中關閉,將 ESLint 註釋新增到對應檔案的頭部的好處是:這些規則雖然對老檔案不起效,但是新檔案都需要遵守這些規則了。
小技巧:如果需要修改的檔案太多了,可以使用我們開發的小工具,批量給檔案新增 ESLint 註釋: https://github.com/xcatliu/add-eslint-comment
編輯器外掛對 ESLint 的支援
所有編輯器對 ESLint 的支援都很好,可以參考這個頁面安裝你的編輯器外掛。
以 VSCode 舉例,在外掛欄中下載安裝 ESLint 之後,編寫 js 程式碼時就會有類似下圖的提示了:
注意:如果提示說 eslint 未安裝,則需要在命令列安裝專案級別的 eslint,或全域性安裝 eslint:
1 |
npm install -g eslint |
VSCode 設定中也可以配置一些 ESLint 選項(以及其他相關選項),比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
{ // 關閉編輯器自帶的 js 檢查,建議關閉 "javascript.validate.enable" : false, // ESLint 在儲存時自動修復錯誤 "eslint.autoFixOnSave": true, // 輸出 ESLint 執行時的 log,ESLint 不生效的時候可以啟用看看 // "eslint.trace.server": "messages", // 配置 ESLint 檢查的檔案型別,這個配置包括 .js, .jsx, .html, .vue "eslint.validate": [ "javascript", "javascriptreact", "html", "vue" ], } |
快來使用 AlloyTeam ESLint 規則吧!