從 0-1 配置 eslint + prettier
前言:為什么需要項目規(guī)范
我們學(xué)習(xí)編程的方式各有不同,對于知識的理解也各有不同,在一天天的編程過后,每個人都養(yǎng)成了自己的代碼習(xí)慣和理解。
代碼習(xí)慣和理解的差異,導(dǎo)致了團隊中會出現(xiàn)各種各樣的 “規(guī)范” 代碼。在你查看自己的代碼時,你可能會覺得自己的代碼看起來比較標(biāo)準(zhǔn),只是有點亂。但是在團隊成員查看你的代碼時,他心里可能會這么想:wtf,他寫的代碼怎么是這個樣子。這種風(fēng)格的代碼就好像是一個公司律師用 excel 規(guī)范自動格式化的沙拉食譜,看起來一點都不靠譜。
這種差異性導(dǎo)致了團隊協(xié)作的效率低下,也影響了項目的健壯性和可維護性。所以,我們需要對代碼風(fēng)格進行規(guī)范。這種規(guī)范不僅可以使代碼風(fēng)格保持統(tǒng)一,并且可以在代碼運行之前就檢測出一些錯誤和 bug,提高協(xié)作開發(fā)效率。
而前端開發(fā)人員最常用的 Javascript 最初設(shè)計出來是只是為了解決一些簡單的網(wǎng)頁互動,是一種弱類型、基于原型的語言。
Javascript 擁有其它語言所沒有的靈活性,這種靈活性帶來了代碼效率的提升,但相應(yīng)也使得代碼編寫具有很大的隨意性。另外 Javascript 的隱式類型轉(zhuǎn)換規(guī)則混亂,允許同名函數(shù)的重復(fù)定義,這就增加了代碼中存在隱患的可能性。
冷笑話:Javascript 權(quán)威指南和 Javascript 語言精粹的厚度區(qū)別。
如果能夠在代碼提交測試之前發(fā)現(xiàn)這些潛在的錯誤,就能夠極大地減輕測試人員的壓力,減少軟件項目的除錯成本。可是 Javascript 作為解釋型語言,解釋器被內(nèi)嵌在對應(yīng)的客戶端,對此表示無能為力,這個任務(wù)只能由專用的代碼檢查工具完成。
在接下來,我會針對上述的這些問題展開講述,首先介紹解決這些問題的工具,然后再介紹借助這項工具來解決團隊規(guī)范和錯誤預(yù)檢問題的步驟方法,最后再用一行命令來整合這些復(fù)雜的步驟,將使用門檻降到最低。
Eslint 和 Prettier
lint
lint 是最著名的 C 語言工具之一,是由貝爾實驗室 SteveJohnson 于 1979 在 PCC(PortableC Compiler) 基礎(chǔ)上開發(fā)的靜態(tài)代碼分析,一般由 UNIX 系統(tǒng)提供。
lint 被用于檢查 C 程序中潛在的錯誤,包括(但不限于)可疑的類型組合、未使用的變量、不可達(dá)的代碼以及不可移植的代碼。lint會產(chǎn)生一系列程序員有必要從頭到尾仔細(xì)閱讀的診斷信息。使用lint的好處是:
-
它可以檢查出被編譯器漏掉的錯誤; -
可以關(guān)聯(lián)很多文件進行錯誤的檢查和代碼分析,具有較強大靈活性
lint 應(yīng)該也算是 lint 界的老祖宗了。
Eslint
有個叫 Nicholas C. Zakas 的人在 2013 年推出了一個 Javascript 的 lint 工具,而 Javascript 也稱作 ECMAScript(簡稱 ES),所以這個工具被叫做 ESlint。
ESLint 是在 ECMAScript/JavaScript 代碼中識別和報告模式匹配的工具,它的目標(biāo)是保證代碼的一致性和避免錯誤。
Eslint 可以在運行代碼前就發(fā)現(xiàn)一些語法錯誤和潛在的 bug,極大地減輕測試人員的壓力,減少軟件項目的除錯成本。同時,Eslint 允許開發(fā)者通過 rules 定義自己的代碼規(guī)范,所以非常適合用于制定團隊代碼規(guī)范。
Prettier
Prettier 是一款代碼格式化工具,用于檢測代碼中的格式問題,比如單行代碼長度、tab長度、空格、逗號表達(dá)式等。在功能職責(zé)上,ESlint 偏向于把控項目的代碼質(zhì)量,而 Prettier 更偏向于統(tǒng)一項目的編碼風(fēng)格。
在 ESlint 推出 --fix 參數(shù)前,ESLint 并沒有自動化格式代碼的功能,要對一些格式問題做批量格式化只能用 Prettier 這樣的工具。并且,Prettier 在代碼風(fēng)格的檢測上比 ESlint 更全面,所以兩者通常是結(jié)合在一起使用的。
常見的標(biāo)準(zhǔn)規(guī)范
在介紹規(guī)范之前,可以先使用 npm i eslint prettier \-g 命令全局安裝 eslint 和 prettier,在后面的教程中都會使用到這兩個全局包。
ESlint 推薦的規(guī)范
ESlint 在默認(rèn)情況下是不開啟任何自定義規(guī)則校驗,只對錯誤的 ES5 語法和標(biāo)準(zhǔn)的語法錯誤進行檢測,比如 const 這種 ES6 語法,還有莫名其妙的分號(如下圖)。
當(dāng)我們在項目目錄下新增 eslintrc.js 文件,并寫入以下內(nèi)容后,將會啟用 ESlint 推薦的規(guī)范:
module.exports = {
root: true,
extends: 'eslint:recommended'
};
復(fù)制代碼
在 ESlint 的推薦規(guī)范中,會有一些內(nèi)置的規(guī)則,比如定義后未使用的變量將會拋出錯誤,使用常量作為循環(huán)條件也會拋出錯誤(如下圖)。
ESlint 的推薦規(guī)范可以避免掉一些錯誤,比如上述兩個錯誤就可以在運行前被檢查到并解決,更多詳細(xì)規(guī)范請參考 ESlint Recommend。
standard
standard 是基于 ESlint Recommend 衍生出來的更嚴(yán)格的規(guī)范。這個規(guī)范和 recommended 大概有 88 處不同,主要是 recommended 很多都是 off, standard 是 error, 比如 單行代碼塊兩邊加空格、禁止使用分號結(jié)尾。
下面的代碼在 recommended 規(guī)范下不會報錯,而在 standard 規(guī)范中會報錯。
recommended 規(guī)范
standard 規(guī)范
先使用 npm i standard eslint-plugin-standard eslint-config-standard \-D 命令安裝 standard 插件,然后在 eslintrc.js 文件中寫入以下內(nèi)容后,將會啟用 standard 規(guī)范:
module.exports = {
root: true,
extends: ['standard']
};
復(fù)制代碼
standard 會比 recommended 更加嚴(yán)格,在代碼風(fēng)格上也做了一些限制。不過它的用戶群體也是比較多的,也不乏一些大家耳熟能詳?shù)摹#ㄈ缦聢D)
詳細(xì)規(guī)范請參考 ESlint Standard。
airbnb
airbnb 規(guī)范是最嚴(yán)格的 ESlint 規(guī)范,列出下面幾點比較明顯的區(qū)別:
-
默認(rèn)必須要分號,而eslint默認(rèn)不添加分號 -
不能使用for循環(huán),推薦使用數(shù)組自帶的 API 完成遍歷工作。 -
當(dāng)你必須使用函數(shù)表達(dá)式(或傳遞一個匿名函數(shù))時,使用箭頭函數(shù)符號。
除了這些以外,還有更多嚴(yán)格的規(guī)則,可以查看 Airbnb 規(guī)范。
在項目中配置 Eslint + Prettier
由于 Eslint 和 Prettier 存在一些相同的規(guī)則,當(dāng)同一個規(guī)則設(shè)置不同時,就會出現(xiàn)很詭異的現(xiàn)象:使用 prettier 格式化的代碼,無法通過 eslint 校驗。
下面,我們就以一份 前端代碼規(guī)范 為例,為一個項目配置一套完整的 ESlint + Prettier 規(guī)范。
配置 .eslintrc.js
我們新建一個 eslintrc.js 文件,寫入以下內(nèi)容,作為我們的初始化配置。(如下)
module.exports = {
root: true // 表示該文件為根配置文件
};
復(fù)制代碼
在上一章的示例代碼中,我們發(fā)現(xiàn) eslint 默認(rèn)只能識別 es5 的語法,所以我們先配置 env 屬性,讓 eslint 支持到 es6 語法,并且我們設(shè)置環(huán)境為 browser(瀏覽器) 或 node(如下)。
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
extends: 'eslint:recommended'
};
復(fù)制代碼
如果使用 standard 標(biāo)準(zhǔn)則不需要額外設(shè)置,standard 支持最新的 ECMAScript 特性。而實驗性的特性,則需要添加 babel-eslint 解析器。
所以,這里我們直接配置 standard 標(biāo)準(zhǔn)和 babel-eslint 解析器,再加上一些自定義規(guī)則后,最后配置的規(guī)則如下:
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint', // 解析一些最新的 es 語法
sourceType: 'module' // 模塊為 ECMAScript 模塊
},
extends: ['standard'], // 使用 standard 標(biāo)準(zhǔn)
rules: {
'no-debugger': 'error', // 禁止在代碼中使用 debugger
quotes: ['error', 'single'], // 單引號
semi: ['error', 'always'] // 代碼需要以分號結(jié)尾
}
};
復(fù)制代碼
在 ESlint 規(guī)范文件配置完成后,我們再來添加 Prettier 配置文件,新建 .prettierrc.js 文件,添加以下內(nèi)容:
module.exports = {
printWidth: 800, // 單行寬度限制
tabWidth: 2, // tab 使用兩個空格
useTabs: false, // 不使用制表符縮進,使用空格縮進
semi: true, // 代碼需要分號結(jié)尾
singleQuote: true, // 單引號
bracketSpacing: true, // 對象左右兩側(cè)需要空格
jsxBracketSameLine: false, // html 關(guān)閉標(biāo)簽換行
arrowParens: 'avoid', // 單參數(shù)的箭頭函數(shù)參數(shù)不需要括號
proseWrap: 'never', // 參考 https://prettier.io/docs/en/options.html#prose-wrap
trailingComma: 'none' // 參考 https://prettier.io/docs/en/options.html#trailing-commas
};
復(fù)制代碼
在配置完成后,我們新建一個文件,測試一下效果。在 src 目錄下新建文件 test.js,填入以下內(nèi)容:
使用自動格式化
從上面可以看出,文件并不符合我們制定的 eslint 規(guī)范,我們下面分別使用 eslint 格式化和 prettier 格式化功能來嘗試修正。
首先,我們在命令行輸入 eslint \--fix src/test.js,然后看看效果(如下圖)
我們可以看到,多余的空格被刪除了,雙引號被換成了雙引號,賦值運算符的左右兩側(cè)也被加上了空格。
接下來,我們先把文件還原,然后使用 prettier \-w src/test.js 命令進行格式化,效果如下圖:
從上圖可以看出,由于我們設(shè)置的 eslint 和 prettier 的規(guī)則一致,所以格式化后的文件也是高度相似的。
這樣一來,我們就完成了代碼規(guī)范格式的統(tǒng)一。
vscode 插件
大家從上面的示例代碼中可以看出,編寫不合規(guī)范的代碼會直接在編輯器中報出錯誤,這是因為上面的示例代碼使用 vscode 展示,并安裝了一些插件來輔助開發(fā)。
下面,我們就來介紹一下這些插件。
我們先通過 vscode 安裝 ESLint 插件(如下圖)
在安裝了 ESLint 插件后,插件會讀取目錄下的 eslint 配置文件,然后對代碼中的錯誤進行檢查后提示出來(如下圖)。
如果我們在 vscode 中設(shè)置了下面這個屬性的話,在保存文件的時候?qū)詣痈袷交a。(如下圖)
下面,我們可以再安裝 Prettier 插件(如下圖)。
在安裝好插件后,使用鍵盤組合鍵 shift + command/ctrl + p 喚起設(shè)置,然后輸入 Format Selection With... 后,按回車鍵,在選項中選擇 Prettier 即可(如下圖)。
在設(shè)置完成后,使用組合鍵 shift + option/alt + f 即可完成對文件的格式化。
這兩個插件還有更多的功能,大家可以自行探索一下。
插件的三兩事
如果你對 vscode 的插件比較熟悉,可以跳過本章節(jié)內(nèi)容。
在 vscode 的插件安裝過程中,有很多童鞋反饋過問題,這里給出一些常見問題的解決方案。
插件不工作
-
全局安裝 npm i eslint prettier -g -
安裝好 vscode插件后,重啟vscode -
如果還是不行的話,升級 vscode
插件未啟用
新版 vscode 需要手動啟用 eslint 插件,在右下角查看 eslint 工作狀態(tài),可以點擊開啟。(如下圖)
啟用后不工作
右下角查看 eslint 工作狀態(tài),點擊會輸出日志。(如下圖)
根據(jù)輸出日志,進行修復(fù),比如上圖就是缺少對應(yīng)插件,安裝即可。
保存沒有按照 eslint 的規(guī)則修復(fù)
這可能是因為你的 vscode 開啟了保存自動格式化(代碼格式化),先打開 首選項 > 設(shè)置,搜索 format on save,然后關(guān)閉這個選項(如下圖)
正常工作
正常工作的 eslint 和 prettier 插件狀態(tài)如下圖所示。
在提交時自動檢測和格式化代碼
在項目開發(fā)過程中,自動格式化并不總是讓人安心的,因為并不是項目組的所有成員都會使用 vscode 插件來做自動格式化。
這樣的情況會導(dǎo)致有一些不規(guī)范的代碼被提交到服務(wù)端,依然會造成團隊規(guī)范不一致的問題,這個時候就需要用到提交時自動檢測和格式化代碼的功能。
接下來,我們將使用 husky 來進行代碼提交時的自動檢測工作。
先使用 npm i husky \-D 安裝依賴,在依賴完成完成后,我們需要使用下面這條命令初始化 husky(如下)
npx husky install && npx husky set .husky/pre-commit "npm run pre-commit"
復(fù)制代碼
上面的命令是初始化 git hook,在 git commit 之前會先執(zhí)行 pre-commit 命令。
所以,我們還需要在項目的 package.json 中,添加 pre-commit,這個命令運行時進行 eslint 檢測(如下)。
"scripts": {
"pre-commit": "eslint src"
}
復(fù)制代碼
接下來,我們運行 git add . 和 git commit \-m 'test' 命令,嘗試提交代碼,會發(fā)現(xiàn)提交失敗,命令行輸出如下圖。
如上圖所示,在提交時檢測到代碼不符合 eslint 規(guī)范,提交失敗了。
如果我們希望在檢測錯誤的同時,自動修復(fù) eslint 語法錯誤,則需要用到 lint-staged,使用 npm i lint-staged \-D 先進行安裝,然后在 package.json 中修改 pre-commit 命令,再添加以下內(nèi)容。
"scripts": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"src/**": [
"eslint --fix"
]
}
復(fù)制代碼
接下來,我們再次運行 git add . 和 git commit \-m 'test' 命令,嘗試提交代碼,輸出如下圖。
從上圖可以看出,在運行 lint-staged 命令后,會通過 eslint \--fix 自動將不符合規(guī)格的代碼正確格式化。
這樣一來,代碼提交時的自動檢測和格式化代碼工作就完成了。
使用腳手架,將配置自動化
手動配置的問題
在完成上述配置后,似乎已經(jīng)大功告成,馬上可以走在規(guī)范編碼的愉快道路上,但是并沒有。
我們仔細(xì)梳理一下會發(fā)現(xiàn),我們需要在某個新項目中配置代碼規(guī)范時,需要進行以下繁瑣的步驟。
-
安裝 Eslint。 -
根據(jù)項目類型安裝對應(yīng)的 ESLint 規(guī)則配置 npm 包。 -
根據(jù)項目類型安裝相關(guān)的插件、解析器等。 -
根據(jù)項目類型配置 .eslintrc .prettierrc 文件。 -
安裝代碼提交檢查 + 自動格式化工具。husky + lint-staged -
配置 package.json。 -
測試及修復(fù)問題。
這些繁瑣的步驟會耗費大量的時間,并且可能還會出現(xiàn)一些錯誤需要額外花時間去排查。這樣的流程對于個人來說可能是個比較好的學(xué)習(xí)機會,但是對于團隊來說確實是個低效的協(xié)作方式。
所以,我們可以借助一些工具來幫忙完成上述工作,這個工具可以根據(jù)配置選擇,生成對應(yīng)的規(guī)范配置,并安裝可以互相兼容的依賴包。
使用腳手架進行自動配置
我們先使用 npm i standard-config-cli \-g 命令全局安裝腳手架工具,然后在對應(yīng)的目錄下運行 jgxl standard 命令。
這里我們以 vue + typescript 命令為例,選擇的配置如下圖。
在初始化完成后,對應(yīng)的幾個配置文件內(nèi)容如下:
.eslintrc.js
.prettierrc.js
package.json
從上面可以看出,我們的規(guī)范配置會根據(jù)所選配置,生成對應(yīng)的規(guī)范配置文件,并且已經(jīng)安裝了相關(guān)版本的依賴。
作為團隊成員,不需要關(guān)心這些規(guī)范的細(xì)枝末節(jié),只需要進行核心業(yè)務(wù)開發(fā)即可。
TIPS:
自動修正功能只能修正部分代碼風(fēng)格規(guī)范,對于一些可能產(chǎn)生隱患的代碼問題不會自動修正(例如:定義而未使用的變量)。
小結(jié)
在代碼風(fēng)格規(guī)范的爭論上,每個人都有自己的理解,永遠(yuǎn)沒有正確的答案。把時間用于細(xì)枝末節(jié)上爭論,不如多把關(guān)注點聚焦在核心業(yè)務(wù)上。
而不管怎樣爭論,總歸會選擇一種風(fēng)格。在這個方面,也需要在個人語義和普適價值上做一個權(quán)衡。
所以,選擇一份前端規(guī)范標(biāo)準(zhǔn)(如 standard),然后保持吧。把時間留下來解決其他有意義的問題!(^____^)/
參考資料:
-
Javascript的10個設(shè)計缺陷 -
eslint -
standard -
prettier -
使用ESLint+Prettier來統(tǒng)一前端代碼風(fēng)格 -
ESLint 在中大型團隊(美團)的應(yīng)用實踐 -
Why (and how) to use eslint in your project -
Automate Your Coding Standard
關(guān)于本文
作者:曬兜斯
https://juejin.cn/post/6954150918086475806
