為什么 husky 放棄了傳統(tǒng)的 JS 配置
點(diǎn)擊上方 前端陽光,關(guān)注公眾號(hào)
回復(fù)加群,加入技術(shù)交流群交流群
前言
husky想必大家都不陌生。作為前端工程化中一個(gè)不可或缺的的工具,它可以向我們的項(xiàng)目中添加git hooks。同時(shí)配合lint-staged可以方便的在代碼提交前進(jìn)行lint。
最近要對一個(gè)老項(xiàng)目添加commit-msg校驗(yàn),同時(shí)要在commit前進(jìn)行eslint校驗(yàn)。之前我也寫過一篇類似的文章你可能已經(jīng)忽略的 git commit 規(guī)范,就直接上手了。
大致流程就是先安裝依賴:
npm i husky -D
然后在package.json配置:
{
"husky": {
"hooks": {
"pre-commit": "npm run test", // 在commit之前先執(zhí)行npm run test命令
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" // 校驗(yàn)commit時(shí)添加的備注信息是否符合我們要求的規(guī)范
}
}
}
然后測試了一下commit操作,好家伙,直接commit成功了。根本沒有對commit-msg做校驗(yàn)。
我就納悶了,之前不都是這樣搞的嗎 ??
沒辦法,去查一下文檔吧。
然后就看到了這個(gè):
原來在 husky(6.0.0)版本做了Breaking change。再看下項(xiàng)目中安裝的版本號(hào):"husky": "^7.0.1"。難怪不生效了,,
之前寫你可能已經(jīng)忽略的 git commit 規(guī)范文章時(shí),用的還是1.0.1的版本。??
既然這樣,我們先來看下作者為什么要做這樣的改動(dòng)吧:
這是作者寫的一篇Why husky has dropped conventional JS config[1],也就是為什么 husky 放棄了傳統(tǒng)的 JS 配置。下面簡單概括一下。
為什么 husky 放棄了傳統(tǒng)的 JS 配置
在 v4 版本之前 husky的工作方式是這樣的:為了能夠讓用戶設(shè)置任何類型的git hooks,husky不得不創(chuàng)建所有類型的git hooks
這樣做的好處就是無論用戶設(shè)置什么類型的git hook,husky都能確保其正常運(yùn)行。但是缺點(diǎn)也是顯而易見的,即使用戶沒有設(shè)置任何git hook,husky也向git中添加了所有類型的git hook。
在當(dāng)時(shí) husky 有過這樣的設(shè)想:有沒有可能讓husky只添加我們需要的git hook呢?作者嘗試過解決這個(gè)問題,但是失敗了。
因?yàn)?code style="margin: 3px;padding: 3px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);">husky需要在兩個(gè)地方進(jìn)行配置才能完成一個(gè)完整的git hook功能。一個(gè)是在package.json中配置git hook所要執(zhí)行的真正命令,一個(gè)是在.git/hooks/中配置相對應(yīng)的git hook。也就是說無論是添加還是刪除git hook就要保證在這兩個(gè)地方同步執(zhí)行對應(yīng)的操作。作者無法找到一個(gè)可靠的方法來同步這兩個(gè)地方的配置,因此失敗了。
新版 husky 的工作原理又是什么呢?
直到 2016 年,Git 2.9引進(jìn)了core.hooksPath,可以設(shè)置Git hooks腳本的目錄,這個(gè)引進(jìn)也就是新版husky改進(jìn)的基礎(chǔ):
可以使用 husky install將git hooks的目錄指定為.husky/使用 husky add命令向.husky/中添加hook
通過這種方式我們就可以只添加我們需要的git hook,而且所有的腳本都保存在了一個(gè)地方(.husky/目錄下)因此也就不存在同步文件的問題了。
ok,了解了這么多,我想你也大概理解作者為什么要做這種破壞性更新的原因了吧。那么我們接著上面的按照新版husky的配置規(guī)則對我們的項(xiàng)目進(jìn)行配置。
新版 husky 實(shí)踐
我們可以直接按照官方文檔的指引來進(jìn)行。
安裝
Install husky
npm install husky --save-dev
Enable Git hooks
npx husky install
如果想安裝后自動(dòng)啟用hooks,可以執(zhí)行:
npm set-script prepare "husky install"
這樣就會(huì)在package.json里面添加一條腳本:
// package.json
{
"scripts": {
"prepare": "husky install"
}
}
prepare是NPM操作生命周期中的一環(huán),在執(zhí)行install的時(shí)候會(huì)按生命周期順序執(zhí)行相應(yīng)鉤子:NPM7:preinstall -> install -> postinstall -> prepublish -> preprepare -> prepare -> postprepare
這樣就會(huì)在代碼根目錄生成如下所示的結(jié)構(gòu):
添加 hook
我們可以使用husky add <file> [cmd]指令來添加一條hook。
commit-msg
在項(xiàng)目中我們會(huì)使用commit-msg這個(gè)git hook來校驗(yàn)我們commit時(shí)添加的備注信息是否符合規(guī)范。在以前我們通常是這樣配置的:
{
"husky": {
"hooks": {
"commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" // 校驗(yàn)commit時(shí)添加的備注信息是否符合我們要求的規(guī)范
}
}
}
在新版husky中$HUSKY_GIT_PARAMS這個(gè)變量不再使用了,取而代之的是$1。所以我們要做如下操作:
執(zhí)行npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'會(huì)在.husky下生成一個(gè)commit-msg的shell文件:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "========= 執(zhí)行commit-msg校驗(yàn) ======="
npx --no-install commitlint --edit $1
此時(shí)如果執(zhí)行git commit操作,會(huì)有如下報(bào)錯(cuò):
提示我們?nèi)鄙?code style="margin: 3px;padding: 3px;max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);">commitlint.config.js文件,這里先安裝依賴:
npm install --save-dev @commitlint/cli @commitlint/config-conventional
然后在根目錄新建一個(gè)commitlint.config.js文件并加入如下內(nèi)容:
module.exports = {
extends: ["@commitlint/config-conventional"]
};
這時(shí)再執(zhí)行commit就會(huì)發(fā)現(xiàn)已經(jīng)生效了:
pre-commit
在commit前,我們可以執(zhí)行測試用例、eslint 校驗(yàn)等,只有這些通過了,才允許提交。這也就是在pre-commit這個(gè)鉤子里需要做的事情。
執(zhí)行npx husky add .husky/pre-commit "npm run test:unit"就會(huì)在.husky下生成一個(gè)pre-commit的 shell 文件:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo "========= 執(zhí)行pre-commit操作(如執(zhí)行測試用例、eslint校驗(yàn)等,可自行添加) ======="
npm run test:unit
讓我們再做一次commit操作:
至此,我們就基于新版husky,完成了項(xiàng)目中commit-msg、pre-commit兩個(gè)鉤子的添加。
參考資料
Why husky has dropped conventional JS config: https://blog.typicode.com/husky-git-hooks-javascript-config/

往期推薦

我組建了技術(shù)交流群,里面有很多 大佬,歡迎進(jìn)來交流、學(xué)習(xí)、共建。回復(fù) 加群 即可。后臺(tái)回復(fù)「電子書」即可免費(fèi)獲取 27本 精選的前端電子書!回復(fù)內(nèi)推,可內(nèi)推各廠內(nèi)推碼
“分享、點(diǎn)贊、在看” 支持一波??
