我們在團隊中開發 Angular 應用程式,經常需要同步每個成員的程式碼格式,與其訂定 Coding Style (代碼風格),倒不如直接用工具強制所有成員用一致的風格進行程式碼排版。本篇文章我將示範用 husky 搭配 prettier 來設定 Git 的 pre-commit
hook,讓每個人在 git commit
之前就自動將變更的程式碼進行排版。
介紹 npm set-script
命令
我在安裝 husky 的時候,看到一個很方便的 npm set-script
命令,他可以透過 npm
命令,使用命令列執行的方式幫你自動設定 package.json
的 scripts
區段內容,自動設定執行腳本內容。
不過我卻發現在我的電腦不能執行 npm set-script
命令,查詢 npm-set-script 官網文件後發現這是 npm 7.x 才有的全新功能。由於我的電腦安裝的是 Node.js 14.17.5 LTS 版本,內建的 npm 是 6.14.14
版,所以不支援這個好用命令。
在 Windows 要升級 npm 必須以管理者身份執行以下 Windows PowerShell 命令才能順利升級到最新版:
Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force
npm install -g npm-windows-upgrade
npm-windows-upgrade -p -v latest
C:\>npm --version
7.21.0
如果是 Linux 或 macOS 的話,很簡單的透過以下命令就可以升級完畢:
npm install –g npm@latest
注意: 只有在第一次設定 husky 的時候才有可能需要升級 npm 版本,就算你不升級版本,手動調整 package.json
也是可以的,不一定要用 npm set-script
來調整 package.json
的內容。對於團隊成員來說,其實 npm 用什麼版本都沒差!
這個段落純粹想記錄一下在 Windows 環境如何升級 npm 版本,但 Angular CLI v12 目前還不支援 npm v7 的版本,所以要降版請用以下命令:
npm-windows-upgrade -p -v 6.14.15
為團隊設定 Coding Style (代碼風格) 自動化設定
這邊我直接以 Angular 12 專案為範例進行實作,講述完整的安裝與設定過程。
-
先透過 Angular CLI 12.2.2 建立一個全新專案:
npm i -g @angular/cli
ng new demo1 --routing --style=css
cd demo1
-
安裝 husky 與 pretty-quick 套件
npm install --save-dev husky prettier pretty-quick
注意: 雖然 pretty-quick 套件本身就包含了 prettier 套件在內,但是 prettier 被註冊在 peerDependencies
裡面,使用 npm
會全自動一併安裝起來,但使用 yarn
的話會跳出警告訊息,必須手動額外安裝。所以我上述命令才連同 prettier
一併安裝!
[3/4] Linking dependencies...
warning " > pretty-quick@3.1.1" has unmet peer dependency "prettier@>=2.0.0".
-
設定 npm 的 prepare
生命週期腳本並執行 husky 安裝
你可以透過 npm pkg set scripts.prepare
命令方便的將 husky install
自動註冊進 npm 的 prepare
生命週期階段(Life Cycle Scripts)。然後 npm run prepare
可以直接執行 husky install
命令,這個動作會自動幫你建立一個 .husky
資料夾:
npm pkg set scripts.prepare="husky install"
npm run prepare
預設 husky install
產生的所有檔案都不會加入 Git 版控,你額外新增的 Hooks 檔案才需要加入版控。
特別值得一提的地方,是這個 prepare
會在執行 npm install
之後自動執行 (必須在沒有附帶任何其他參數下執行 npm install
才行)。如果你寫的專案是會發布到 npm registry 的話,prepare
會在 npm publish
與 npm pack
之前自動執行。詳細的執行生命週期請見 Life Cycle Operation Order 文件。
請不要將 husky install
註冊在 postinstall
生命週期階段!(Typicode's blog - Why husky doesn't autoinstall anymore)
-
設定 husky 的 pre-commit
Hook
這裡我們設定 pre-commit
Hook,讓團隊成員在執行 git commit
之前,就會自動透過 pretty-quick 的 pretty-quick --staged
命令對 Git 暫存的檔案 (Staged files) 進行程式碼編排,而且是參照 .prettierrc.json
, .prettierignore
與 .editorconfig
的設定進行,確保團隊的程式撰寫風格一致。以下命令會產生一個 .husky/pre-commit
檔案,這個檔案需要加入到 Git 版控之中。
npx husky set .husky/pre-commit "npx pretty-quick --staged"
這個 npx pretty-quick --staged
命令,主要做兩件事:
- 找出目前 Git 版控中,已經被加入到 Staged 狀態的檔案清單
- 將這些工作目錄中的檔案透過 Prettier 排版後,直接加入到 Git 的 Staged 狀態中
簡單來說,他會在無形之中,默默的將你的程式碼排版成 Prettier 想要排版的樣子。你想要用自己的方式排版怎麼辦呢?沒錯!Prettier 就是這麼霸道,也沒什麼好商量的,整個團隊都用同一套規則集排版程式碼就對了,如此一來,你就不要再花時間想程式碼風格這件事情了!
-
加入 .prettierignore
檔案 (不要透過 Prettier 排版的檔案清單)
我基本上習慣將專案根目錄下的 package.json
與 package-lock.json
加入到 .prettierignore
檔案中,畢竟這些檔案都是透過 npm
工具在更新的居多,沒必要特別排版過。除此之外,我也會把 Visual Studio Code 的設定檔 (.vscode/*
) 也都自動排除在 Prettier 掃描的清單中。最後,Angular 建置後的檔案通常也不用自動格式化。
# IDE/Editor
.vscode
.idea
# Package Manager
package.json
package-lock.json
yarn.lock
# TypeScript-related
tsconfig.json
tsconfig.app.json
tsconfig.spec.json
# Angular-related
**/assets/**/*
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
-
加入 .prettierrc.json
檔案
其實 Prettier 可以設定的選項並不多,但有些地雷。其中初學者最容易遇到的問題,就是 .prettierrc.json
與 .editorconfig
設定不一致的情況。在編輯器中有兩種不同的風格,絕對會遇到許多問題,所以請務必設定正確!
你要是從網路上找的許多的 .prettierrc
範例,都會叫你設定 tabWidth
與 useTabs
這兩項。但是這兩個設定會跟 .editorconfig
中的 indent_size
與 indent_style
完全重複,如果你剛好兩邊的設定不相同,就可能會出現非常詭異的情況,有時候甚至覺得會不知所措,也就是俗稱「鬼打牆」的情況。所以我一般都會特別看過兩邊的設定是否一致,這點真的非常重要!
{
"tabWidth": 2,
"useTabs": false,
"printWidth": 100,
"bracketSpacing": true,
"singleQuote": true,
"trailingComma": "es5",
"semi": true,
"overrides": [
{
"files": [
"*.json",
".babelrc"
],
"options": {
"parser": "json-stringify"
}
},
{
"files": [
"*.jsonc",
"tsconfig*.json"
],
"options": {
"parser": "json"
}
},
{
"files": [
"*.js",
"*.cjs",
"*.mjs"
],
"options": {
"parser": "babel"
}
},
{
"files": [
"*.ts"
],
"options": {
"parser": "typescript"
}
}
]
}
Angular CLI 透過 ng new
產生的專案範本,其 .editorconfig
檔案中的 indent_size
設定值預設為 2
!
請注意: 修改 .editorconfig
檔案設定之後,編輯器不一定會立刻生效 (通常會),當你遇到靈異事件的時候,請記得「重開治百病」這句至理名言,將編輯器重開即可!
-
調整 Visual Studio Code 的工作區設定
因為 Visual Studio Code 除了會參考 .editorconfig
編輯器設定外,還有不同程式語言就會有不同的 Formatter 擴充套件,而且不同 Formatter 的格式化差異可能很大,VSCode 本來就內建許多語言的 Formatter,但使用者還可以自行加裝不同的 Formatter 擴充套件,所以開發者的 Formatter 可能會非常混亂!
為了要讓團隊的開發風格趨於一致,也希望團隊成員不要花任何心思在排版上,所以 Visual Studio Code 的設定其實是非常重要的。
我們可以在專案目錄下建立 .vscode/settings.json
檔案,讓所有人在「儲存」的時候就自動用我們指定的 Prettier Formatter 排版好。不過,就算使用者沒有設定,由於我們也設定了 pre-commit
hook,所以最終在 git commit
的時候,程式碼還是會自動格式化的!但我們真正希望的是,不要有太多的意外,不要有太多的靈異事件,最好我們在編輯器中看到的程式碼,就是最終 Prettier 幫我格式化過後的格式!
請設定以下 .vscode/settings.json
檔案內容:
{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.formatOnSave": true
}
再建立一個 .vscode/extensions.json
檔案,建議成員一定要安裝 EditorConfig 與 Prettier - Code formatter 擴充套件:
{
"recommendations": [
"angular.ng-template",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode"
]
}
-
將修改加入 Git 版控
走到這一步已經全部設定完成,所以從現在開始 git commit
就會開始套用 Prettier 的設定,並自動將已加入 Git Staged 的原始碼進行格式化並加入版控。
git commit
不過,若你想讓特定版本跳過 Git 的 pre-commit
hook 的話,可以考慮用以下命令直接將現有版本加入版控:
git commit --no-verify
檢查所有原始碼的排版後風格
在正式執行 git commit
自動排版之前,我們可以透過以下命令,先手動執行看看感覺,驗證一下排版過的格式是否滿意。
-
使用 Prettier 對整個專案所有原始碼進行檢查
只要有出現 [warn]
字樣,就代表該檔案會被格式化,但不會真的寫入:
npx prettier --check .
-
使用 Prettier 對整個專案所有原始碼進行格式化
底下命令則會將原始碼格式化之後寫入檔案,你就可以看出這些檔案的排版風格:
npx prettier --write .
我會建議啟用 husky + pretty-quick 之後的第一個 Git 版本,可以用 npx prettier --write .
先進行一次格式排版,讓團隊都基於相同的基礎下進行版控,如此一來可以減少日後版本追蹤上的困擾。
但是如果你的程式碼很多,團隊也不小,專案也尚未進入穩定發展的狀態,這代表團隊成員還在積極開發中,這樣我就會建議可以跳過這個步驟,否則突然的變動可能會造成數千支檔案同時調整過,這樣不但會增加衝突發生的機率,同時也難以透過 git diff
比對排版之前與排版之後的版本變更。
-
使用 pretty-quick 對已加入 Git Staged 的原始碼進行檢查
如果透過以下命令檢查出有檔案尚未符合格式要求,該命令的 Exit Code 為 1
,這很適合在 CI 階段的時候檢查格式是否符合標準,也可以查出有成員沒有正確設定 husky + pretty-quick 等工具。
npx pretty-quick --check
-
使用 pretty-quick 對已加入 Git Staged 的原始碼進行格式化
以下命令則會直接對檔案進行格式化,並自動寫入格式化後的版本,但不會自動幫你 git add
加入暫存的變更 (Staged)
npx pretty-quick --bail
後記
要搞清楚 Visual Studio Code 的 Formatter, EditorConfig, Prettier, pretty-quick, husky, Git Hooks 彼此之間的連動關係,除了要經年累月的背景知識加持,還要對每套工具的正確理解,才有辦法真正釐清整個來龍去脈。另一方面,這些不同工具之間都有各種不同的使用情境,如果再加上工具新舊版本的差異,可以想見網路上可以找到的文章非常的混亂,可能以前適用的設定,到今日就不適合了。所以看別人的部落格文章時,絕對不能照抄設定,一定要理解消化之後才能正確使用。
我之前有很長一段時間覺得 Prettier 很難用,而且跟 Visual Studio Code 內建的格式化風格差別很大,常常在 VSCode 格式化之後,透過 Prettier 又格式化成另一種格式,覺得非常麻煩。今天整理這篇文章,算是完整解決了我多年來的困擾,非常開心啊! 😄
現在我們公司成長到快 50 人了,團隊的開發效率變成一件非常重要的事情,你很難想像我花多少時間整理這些資訊,但也唯有這樣的研究,才能讓團隊成員更輕鬆無腦的參與團隊協作,所以花這些時間我覺得蠻值得的!🙂
相關連結