前言
husky
想必大家都不陌生。作為前端工程化中一個不可或缺的的工具,它可以向我們的專案中新增git hooks
。同時配合lint-staged
可以方便的在程式碼提交前進行lint
。
最近要對一個老專案新增commit-msg
校驗,同時要在commit
前進行eslint
校驗。之前我也寫過一篇類似的文章你可能已經忽略的 git commit 規範,就直接上手了。
大致流程就是先安裝依賴:
npm i husky -D
然後在package.json
配置:
{
"husky": {
"hooks": {
"pre-commit": "npm run test", // 在commit之前先執行npm run test命令
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" // 校驗commit時新增的備註資訊是否符合我們要求的規範
}
}
}
然後測試了一下commit
操作,好傢伙,直接commit
成功了。根本沒有對commit-msg
做校驗。
我就納悶了,之前不都是這樣搞的嗎 ?
沒辦法,去查一下文件吧。
然後就看到了這個:
原來在 husky(6.0.0)版本做了Breaking change
。再看下專案中安裝的版本號:"husky": "^7.0.1"
。難怪不生效了,,
之前寫你可能已經忽略的 git commit 規範文章時,用的還是1.0.1
的版本。?
既然這樣,我們先來看下作者為什麼要做這樣的改動吧:
這是作者寫的一篇Why husky has dropped conventional JS config,也就是為什麼 husky 放棄了傳統的 JS 配置
。下面簡單概括一下。
為什麼 husky 放棄了傳統的 JS 配置
在 v4
版本之前 husky
的工作方式是這樣的:為了能夠讓使用者設定任何型別的git hooks
,husky
不得不建立所有型別的git hooks
這樣做的好處就是無論使用者設定什麼型別的git hook
,husky
都能確保其正常執行。但是缺點也是顯而易見的,即使使用者沒有設定任何git hook
,husky
也向git
中新增了所有型別的git hook
。
在當時 husky
有過這樣的設想:有沒有可能讓husky
只新增我們需要的git hook
呢?作者嘗試過解決這個問題,但是失敗了。
因為husky
需要在兩個地方進行配置才能完成一個完整的git hook
功能。一個是在package.json
中配置git hook
所要執行的真正命令,一個是在.git/hooks/
中配置相對應的git hook
。也就是說無論是新增還是刪除git hook
就要保證在這兩個地方同步執行對應的操作。作者無法找到一個可靠的方法來同步這兩個地方的配置,因此失敗了。
新版 husky 的工作原理又是什麼呢?
直到 2016 年,Git 2.9
引進了core.hooksPath
,可以設定Git hooks
指令碼的目錄,這個引進也就是新版husky
改進的基礎:
- 可以使用
husky install
將git hooks
的目錄指定為.husky/
- 使用
husky add
命令向.husky/
中新增hook
通過這種方式我們就可以只新增我們需要的git hook
,而且所有的指令碼都儲存在了一個地方(.husky/目錄下)因此也就不存在同步檔案的問題了。
ok,瞭解了這麼多,我想你也大概理解作者為什麼要做這種破壞性更新的原因了吧。那麼我們接著上面的按照新版husky
的配置規則對我們的專案進行配置。
新版 husky 實踐
我們可以直接按照官方文件的指引來進行。
安裝
Install husky
npm install husky --save-dev
Enable Git hooks
npx husky install
如果想安裝後自動啟用hooks
,可以執行:
npm set-script prepare "husky install"
這樣就會在package.json
裡面新增一條指令碼:
// package.json
{
"scripts": {
"prepare": "husky install"
}
}
prepare
是NPM
操作生命週期中的一環,在執行install
的時候會按生命週期順序執行相應鉤子:
NPM7:preinstall -> install -> postinstall -> prepublish -> preprepare -> prepare -> postprepare
這樣就會在程式碼根目錄生成如下所示的結構:
新增 hook
我們可以使用husky add <file> [cmd]
指令來新增一條hook
。
commit-msg
在專案中我們會使用commit-msg
這個git hook
來校驗我們commit
時新增的備註資訊是否符合規範。在以前我們通常是這樣配置的:
{
"husky": {
"hooks": {
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" // 校驗commit時新增的備註資訊是否符合我們要求的規範
}
}
}
在新版husky
中$HUSKY_GIT_PARAMS
這個變數不再使用了,取而代之的是$1
。所以我們要做如下操作:
執行npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
會在.husky
下生成一個commit-msg
的shell
檔案:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "========= 執行commit-msg校驗 ======="
npx --no-install commitlint --edit $1
此時如果執行git commit
操作,會有如下報錯:
提示我們缺少commitlint.config.js
檔案,這裡先安裝依賴:
npm install --save-dev @commitlint/cli @commitlint/config-conventional
然後在根目錄新建一個commitlint.config.js
檔案並加入如下內容:
module.exports = {
extends: ["@commitlint/config-conventional"]
};
這時再執行commit
就會發現已經生效了:
pre-commit
在commit
前,我們可以執行測試用例、eslint 校驗等,只有這些通過了,才允許提交。這也就是在pre-commit
這個鉤子裡需要做的事情。
執行npx husky add .husky/pre-commit "npm run test:unit"
就會在.husky
下生成一個pre-commit
的 shell 檔案:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "========= 執行pre-commit操作(如執行測試用例、eslint校驗等,可自行新增) ======="
npm run test:unit
讓我們再做一次commit
操作:
至此,我們就基於新版husky
,完成了專案中commit-msg
、pre-commit
兩個鉤子的新增。