注意事項#
本文預設開發環境是 VSCode,團隊內盡可能統一開發環境,避免編輯器差異、插件不相容的問題。
以下提到的工具核心都是配置檔,並且這些配置檔通常都能透過多種格式配置,例如 .js
、.yaml
、.json
或者直接在 package.json
中配置。後面不再贅述相關設定,具體配置形式可以在官方文檔查詢,本文僅解析部分配置項目。
程式碼風格#
程式碼風格一致是專案協作的基石,使用 ESLint 和 Prettier 可以避免由於程式碼格式不一致帶來的程式碼合併衝突,也可以提高程式碼可讀性和可維護性。雖然在認識 ESLint 和 Prettier提到過,但是下面想要作為升級版講得更完整一點。
ESlint#
本文介紹的第一個工具是 ESlint,其功能是:
- 提供程式碼規範,例如:建議你使用
===
而不是==
,建議你未修改過的變數使用const
而不是let
等這樣的規則 - 其次是格式化程式碼,控制縮排換行之類的問題
安裝#
npm install --save-dev eslint
VSCode 插件#
在專案中安裝了 ESlint 確實提供了檔案校驗和整理的介面,但實際上在寫程式碼過程中格式化總不能每次都自己調一下 api 處理當前檔案,這個時候就需要使用 ESlint 插件。安裝插件後可以透過快捷鍵調用 eslint api 處理當前檔案,甚至在保存時自動格式化當前檔案,在編碼窗口也會使用黃線和紅線標註警告和錯誤程式碼。
安裝完 ESlint 本體和 VSCode 插件你可以使用一些基本功能,但要與 React、Vue、TS 等檔案配合使用需要安裝相應插件(注意這裡說的是 ESlint 的 plugins,跟前面提到的 VSCode 插件沒有關係),後面會詳細介紹插件(plugins)相關問題。
配置#
先看一眼 ESlint 的配置檔,它用於配置和擴充 ESLint 規則,這是一個例子:
{
"root": true,
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"parser": "@typescript-eslint/parser",
"parserOptions": { "project": ["./tsconfig.json"] },
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/strict-boolean-expressions": [
2,
{
"allowString": false,
"allowNumber": false
}
]
},
"ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
}
接著詳細解析一下 extends、plugins、rules 三個配置。
Extends#
上面提到的規則有一兩百條,要每條手動配置不現實,我們可以使用 Extends。
Extends 是配置的集合,添加了 Extends 等於添加了一組配置。配置 extends 的值時可以忽略包名的 eslint-config-
前綴。
很多大廠都有自己的一套規範,例如前端程式碼規範領域著名的 airbnb,他們的配置檔是 eslint-config-airbnb,安裝之後使用時只需要這麼寫:
{
"extends": "airbnb"
}
不過…… 其實個人建議用 eslint:recommended
或者 standard
而不是 airbnb
,因為 airbnb 實屬管太多,例如 no-plusplus
和 no-underscore-dangle
正常使用並沒有什麼問題,他也給開了,跟原來的編碼習慣差距比較大所以選擇不用了 😂。
當然,配置集合還有其他選擇,例如 eslint-config-alloy;你還可以發布自己的配置集合,其實這也是官方推薦的做法。
Plugins#
Plugins 比 Extends 更強勁,不止可以補充配置,更能新增 ESLint 自定義規則。配置 plugins 的值時可以忽略包名的 eslint-plugin-
前綴;因為 plugin 中也可以包含配置集合,使用 plugin 中的配置集合時可以使用plugin:包名/配置名
的格式,如 plugin/essential。
在安裝 eslint-plugin-vue 之後可以這樣添加插件,就能在 ESLint 中新增一大堆 Vue 的規則(注意只是新增規則,並未配置規則是否使用):
{
// ...
"extends": ["plugin:vue/essential"],
"plugins": ["vue"]
// ...
}
各種語言詳細的配置這裡就不一一贅述了,eslint-plugin-xxx
的文檔一般會提供比較完善的幫助。
Rules#
在 extends 添加完規則集合之後,很可能還要根據自己習慣微調一些規則,這時候就可以在 rules
配置一些單條規則。
規則的等級有三種:
- "off" or 0 - turn the rule off
- "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code)
- "error" or 2 - turn the rule on as an error (exit code is 1 when triggered)
配置方式大概長這樣(一些特殊規則會有其他配置項,可以在規則對應頁面獲取相關資訊):
{
"plugins": ["plugin1"],
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["error", "double"],
"plugin1/rule1": "error"
}
}
其他問題#
配置未生效:
在更新完 .eslintrc
卻發現新配置在 VSCode 沒有生效時,可以透過 ctrl shift P 然後選 Reload Window
快速重啟 ESlint 插件。
VSCode 保存時自動格式化配置,修改 settings.json
:
// settings.json
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
// "editor.formatOnSave": true,
}
Prettier#
Prettier 是一個現代化的程式碼格式化工具。相比 ESLint,它專注於程式碼格式化,可以處理多種語言,包括 JavaScript、CSS、SCSS、markdown、yaml 等。Prettier 補全了 ESLint 只處理 js 系檔案的問題,但對於 js 這個兩者皆可處理的交集,仍然需要一些額外的相容操作。
安裝#
npm install --save-dev --save-exact prettier
注意一定要加 --save-exact
,因為不同版本的 prettier 處理某些格式時會有差異,為了保證團隊全員格式相同,必須統一 prettier 版本。
VSCode 插件#
原理跟 ESLint 一樣,npm 安裝只提供 api,安裝 VSCode 插件才能在編輯器方便格式化。
配置#
By far the biggest reason for adopting Prettier is to stop all the ongoing debates over styles.
Prettier 為了讓大家少在格式上爭吵,只提供了少數配置項,這樣大家只要在這幾個項目中爭吵就可以了(誤)。下面這些是 Prettier 幾乎全部配置,檔名為 .prettierrc
:
{
"arrowParens": "always",
"bracketSameLine": true,
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxSingleQuote": false,
"printWidth": 80,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": true,
"singleAttributePerLine": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false,
"vueIndentScriptAndStyle": false
}
ESlint 相容#
之前有在用 eslint 和 prettier 讓跨 IDE 協作更舒服提到可以手動讓 ESlint 和 Prettier 相容,不過那只是因為使用不同編輯器方便同步的一種方法,這裡再介紹一下用 ESlint 插件相容的方法。
要完整使用 ESLint 接替 Prettier 的工作需要 eslint-plugin-prettier。它的原理是使用 eslint-config-prettier 僅關閉所有 prettier 相關規則,然後透過插件把 Prettier 的規則轉到 ESlint 一起校驗。要做到上述全部操作只需要下面一行配置:
{
"extends": ["plugin:prettier/recommended"]
}
因為配置 "extends": ["plugin:prettier/recommended"]
後相當於填充了以下一組配置:
{
"extends": ["prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
"arrow-body-style": "off",
"prefer-arrow-callback": "off"
}
}
其他問題#
特殊規則:
注意 prettier 覆蓋了的一些特殊規則,例如會預設關掉 vue/html-self-closing
等規則,請再另外根據自己需求再 rules
配置。
提交門禁#
以上是統一程式碼格式相關的工具,但沒有保證提交到程式碼庫的程式碼經過格式化,使用 husky 可以在提交前對程式碼檢查,保存提交的程式碼符合團隊規範。
Husky#
Git hooks made easy 🐶 woof!
husky 為 npm 專案提供介入 Git hook 的能力,它支持所有 Git hook,但我們一般只會用到 pre-commit
和 commit-msg
。
pre-commit
用於提交前的檢查,commit-msg
用於提交信息檢測。
# 安裝 husky
npm install husky --save-dev
# 啟用 Git hook
npx husky install
# 配置 npm 的 prepare 命令,用於依賴安裝後自動運行特定腳本
# 注意,使用 pkg 需要 npm 7 以上版本
npm pkg set scripts.prepare="husky install"
無法使用 pkg
可以直接在 package.json
配置:
{
"scripts": {
"prepare": "husky install"
}
}
之後使用 husky add <file> [cmd]
的格式添加 hook 觸發的命令即可,接著介紹一下在 pre-commit
和 commit-msg
分別要使用的 lint-staged
和 commitlint
。
lint-staged#
Run linters against staged git files and don't let 💩 slip into your code base!
對於新接入 ESLint 的程式碼庫,每次提交都檢測所有檔案,不通過就不允許提交的話,是不是有點過分了?使用 lint-staged 可以只校驗當前提交的檔案,讓你的專案漸進式更新程式碼風格。
安裝#
npm install --save-dev lint-staged
配置#
配置檔名 .lintstagedrc
,因為 lint-staged 的配置比較簡短,可以直接寫在 package.json
的 lint-staged
對象裡。
配置範例:
{
"src/**/*.{ts,js}": ["eslint --cache --fix"],
"src/**/*.{json,less}": ["prettier --write"]
}
husky 觸發#
# 在已安裝 husky 的前提下運行
npx husky add .husky/pre-commit "npx lint-staged"
commitlint#
commitlint 可以檢測提交信息是否符合規範。
簡單來說就是這樣的格式:type(scope?): subject
,實際例子可能是這樣的:feat(blog): add comment section
。詳細規範可以查看理解語義化 Commit。
安裝#
npm install --save-dev @commitlint/config-conventional @commitlint/cli
配置#
配置檔名 .commitlintrc
,配置範例:
{
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat', // 新功能(feature)
'fix', // 修補bug
'docs', // 文檔(documentation)
'style', // 格式(不影響程式碼運行的變動)
'refactor', // 重構(即不是新增功能,也不是修改bug的程式碼變動)
'test', // 增加測試
'revert', // 回滾
'chore', // 構建過程或輔助工具的變動
'perf', // 性能優化
'types' // typescript類型定義檔更改
]
],
'type-case': [0],
'type-empty': [0],
'scope-empty': [0],
'scope-case': [0],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 72]
}
}
可以在 Github 查看更完整的填寫範例。
husky 觸發#
# 在已安裝 husky 的前提下運行
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
包管理器#
使用固定包管理器,一般選擇有以下幾種:
想快速了解幾種管理器的差異可以查看《速通 npm、yarn、pnpm》。同時強烈推薦《JavaScript package managers compared: npm, Yarn, or pnpm?》,講得全面且清楚,下面貼一張來自此文的性能對比圖:
可以按照喜好和相容性自行選擇,但是無論選擇哪個管理器,非必要時,不要刪除 lock 檔!!! 在安裝依賴時,管理器需要計算依賴版本,很耗時,有 lock 可以直接按 lock 列表安裝。
但是有 lock 的時候,依賴的下載地址是固定的,所以配倉庫會不生效,持續集成時需要注意。
P.S. 不同管理器在配 husky 的時候可能有些差異
引擎版本#
如果保留了依賴的 lock 檔,那麼記錄當前應用適配的 node 版本也是十分必要的,不同 node 版本會造成下載的依賴不一樣、甚至依賴根本不適配當前 node 版本;另外,還有一些舊專案,必須用舊的 node 版本才能運行,但是接手的時候根本不知道用的那個版本,就十分讓人無奈。
為解決這個問題,我們可以在 package.json
指定 node 和 npm 版本:
{
"engines": {
"node": ">=0.10.3 <15",
"npm": "~1.0.20"
}
}
團隊人多、專案多時,很可能出現大家版本不一樣的情況,在必要時,可以使用 node 版本管理器,這裡推薦三款:
- nvm unix, macOS nvm-windows Windows
- n macOS, Linux
- fnm macOS, Windows, Linux
基本上可以做到一行命令安裝版本、一行命令切換版本,十分方便。
.npmrc#
相信檔名帶著 rc
已經很熟悉了,.npmrc
作用就是添加專案級別的 npm 配置,例如:
- 改倉庫,有的公司有自己的鏡像,可以在
.npmrc
配置,不用每次都在安裝的時候帶一串參數,也不會影響全局配置 - 還可以添加一些二進制包的下載地址,例如那個煩人的 sass
registry=https://mirrors.huaweicloud.com/repository/npm/
sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
分支策略#
選擇一種分支策略,可以選擇以下三種策略,也可以以這些策略為基礎調整出一個最適合自己團隊的策略:
總結#
- 使用 ESlint 和 Prettier 控制程式碼規範和程式碼風格
- 添加 VSCode 插件极速格式化當前檔案
- 添加提交門禁,保證上傳到版本控制的程式碼符合規範
- 使用 husky 添加提交鉤子,控制提交是否成功
- lint-staged 用於只檢查本次提交檔案是否符合要求,利於專案漸進式控制程式碼規範
- commitlint 保證提交信息可讀性
- 團隊內使用統一的包管理器,保留依賴 lock 檔
- 固定引擎版本,防止依賴變化,也能避免舊專案不知道使用什麼版本運行的窘境
- 使用
.npmrc
固定倉庫等配置 - 選擇一種分支策略,使程式碼歷史更有序
各位看完覺得有遺漏或者有什麼不懂我再補充!