
前提
本文并不單獨講解 ESLint 和 Prettier 如何配置和運作。
問題
想在團隊中推行一定的代碼規範,并給不符合規範的代碼做檢測和提示。
方案
代碼規範校驗使用 ESLint,但是一開始 ESLint 隻有檢測告訴你哪裡有問題,常常出現的情況就是一堆 warning,改起來很痛苦。後來 ESLint 提供了
$ ESLint filename --fix
的指令可以自動幫你修複一些不符合規範的代碼。Prettier 是一個代碼格式化工具,可以幫你把代碼格式化成可讀性更好的格式,最典型的就是一行代碼過長的問題。
Lint和prettier差別
那 ESLint 和 Prettier 的差別是什麼呢?eslint(包括其他一些 lint 工具)的主要功能包含代碼格式的校驗,代碼品質的校驗。而 Prettier 隻是代碼格式的校驗(并格式化代碼),不會對代碼品質進行校驗。代碼格式問題通常指的是:單行代碼長度、tab長度、空格、逗号表達式等問題。而代碼品質問題指的是:未使用變量、三等号、全局變量聲明等問題。
Lint和Prettier配合使用
為什麼要兩者配合使用?因為,第一在 ESLint 推出 --fix 參數前,ESLint 并沒有自動化格式代碼的功能,要對一些格式問題做批量格式化隻能用 Prettier 這樣的工具。第二 ESLint 的規則并不能完全包含 Prettier 的規則,兩者不是簡單的誰替代誰的問題。但是在 ESLint 推出 --fix 指令行參數之後,如果你覺得 ESLint 提供的格式化代碼夠用了,也可以不使用 Prettier。
ESLint 和 Prettier 互相合作的時候有一些問題,對于他們交集的部分規則,ESLint 和 Prettier 格式化後的代碼格式不一緻。導緻的問題是:當你用 Prettier 格式化代碼後再用 ESLint 去檢測,會出現一些因為格式化導緻的 warning。這個時候有兩個解決方案: 1. 運作 Prettier 之後,再使用 eslint --fix 格式化一把,這樣把沖突的部分以 ESLint 的格式為标準覆寫掉,剩下的 warning 就都是代碼品質問題了。 2. 在配置 ESLint 的校驗規則時候把和 Prettier 沖突的規則 disable 掉,然後再使用 Prettier 的規則作為校驗規則。那麼使用 Prettier 格式化後,使用 ESLint 校驗就不會出現對前者的 warning。
為什麼不能先使用 ESLint 再使用 Prettier。針對方案1,如果你後使用 Prettier,那麼格式化後送出的代碼在下一次或者别人 checkout 代碼後是通不過 lint 校驗的。針對方案2,其實是可以的,但是本人在實踐中看社群方案的時候有提到某些情況下 eslint --fix 和 prettier 混用會出現格式問題。是以保險起見還是先用 perttier 格式化,再用 eslint 指令校驗,而不用 eslint --fix 指令去格式化。
方案一實踐
一、安裝 prettier-eslint(Tip:所有方案前提是你已經安裝 eslint 和 prettier 相關包):
$ npm install --save-dev prettier-eslint prettier-eslint-cli
二、運作
$ npm prettier-eslint "src/**/*.js"
prettier-eslint 會一次執行 prettier 和 eslint --fix 指令。整個流程是:Code ➡️ prettier ➡️ eslint --fix ➡️ Formatted Code。prettier-eslint 的各種參數請參看 https://github.com/prettier/prettier-eslint-cli 。
方案二實踐
方案二的思路主要是在 eslint 的規則配置檔案上做文章,安裝特定的 plugin,把其配置到規則的尾部,實作 prettier 規則對 eslint 規則的覆寫。
一、安裝 plugin:
$ npm install --save-dev eslint-config-prettier
二、在 .eslintrc.* 檔案裡面的 extends 字段添加:
{
"extends": [
...,
"已經配置的規則",
+ "prettier",
+ "prettier/@typescript-eslint"
]
}
我使用的是 TypeScript,是以 plugin 的名字是 prettier/@typescript-eslint。
如果你想 disable 掉更多的規則可以是如下:
{
"extends": [
...,
"已經配置的規則",
"prettier",
"prettier/@typescript-eslint",
"prettier/babel",
"prettier/flowtype",
"prettier/react",
"prettier/standard",
"prettier/unicorn",
"prettier/vue"
]
}
看名字應該能猜到每個對應的是 disable 哪些規則了吧。
三、完成上述兩步可以實作的是運作 eslint 指令會按照 prettier 的規則做相關校驗,但是還是需要分别運作 prettier 和 eslint 指令。社群有一個方案整合了上述兩步,在使用 eslint --fix 時候,實際使用 prettier 來替代 eslint 的格式化功能。 安裝:
$ npm install --save-dev eslint-plugin-prettier
修改 .eslintrc.*
{
"extends": [
...,
"已經配置的規則",
"plugin:prettier/recommended"
]
}
這個時候你運作 eslint --fix 實際使用的是 Prettier 去格式化檔案。eslint-plugin-prettier 具體詳細的配置見:https://github.com/prettier/eslint-plugin-prettier
和VSCode內建使用
上面所有講到的内容都是在你寫完代碼去校驗的,使用的是指令行工具。如果你是一個新手,對規範不是很熟悉,那麼碰到的問題就是寫完代碼運作指令行工具後産生海量的 warning。這個時候改起來真的很打擊積極性。如果能夠在寫的代碼的時候讓編輯器提示就能及時改正了。自然我們社群也提供了很多方案,各家的編輯器 Atom、Sublime、VSCode 等主流的編輯器都有相關的插件。我就以 VSCode 為例:
一、下載下傳 ESLint Extension
二、配置 .eslintrc.*
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended'
],
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module'
},
// 其他配置
};
```
三、因為我使用了 TypeScript 是以 .eslintrc.* 配置項的值和 javascript 有點不一樣,但是原理是一樣的。如果你沒有使用 TypeScript 那麼到上面步驟就結束了。但是 VSCode 的 ESLint 插件沒有天然支援 ts 檔案,是以我們還必須自己建立一個設定檔案。在項目根目錄下建立 .vscode/settings.json 檔案,内容如下:
```json
{
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "typescript",
"autoFix": true
},
{
"language": "typescriptreact",
"autoFix": true
}
]
}
你就可以看到編輯器對代碼有實時提示了。
強制校驗和格式化
講到這裡兩個工具配合使用已經講好了,但是這些步驟都依賴于人工自覺,要做到一點點強制功能,我們就可以用到 husky lint-staged 來在 git commit 前強制代碼格式化和代碼校驗。 一、安裝
$npm install --save-dev husky lint-staged
二、修改 package.json:
{
"name": "project-name",
...,
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
+ "prettier --write",
+ "eslint",
+ "git add"
+ ]
+ },
}
三、那麼在運作 git commit 時候,自動會先去運作 prettier --write 格式化代碼,再運作 eslint 校驗代碼是否符合規範。這兩步都通過後才會送出代碼。如果任何一步失敗,則會停止送出。
如果你使用方案一,lint-staged 配置的指令:
{
"name": "project-name",
...,
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
+ "prettier-eslint",
+ "git add"
+ ]
+ },
}
如果你使用了方案二中的 eslint-plugin-prettier,lint-staged 配置的指令:
{
"name": "project-name",
...,
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
+ "eslint --fix",
+ "git add"
+ ]
+ },
}
參考文獻
- https://eslint.org/
- https://prettier.io/
- https://restishistory.net/blog/whats-the-difference-between-eslint-and-prettier.html
如果使用的是 TypeScript:
- ESLint如何運用到TS項目
- 如何和Prettier配合使用