本章主要说明结合了 Git Hooks 与 NPM Hooks 的 husky 仓库。
以实现在 git commit 操作时对代码进行 lint-staged 操作。
1.yorkie & husky
1-1.yorkie
yorkie 是 fork 自 husky 的项目。目前较新版本是yorkie@2.0.0
项目中执行
git init,以支持yorkie在.git/hooks目录下创建hooks文件。它内置了
install生命周期钩子,在安装该依赖包时,会自动在.git/hooks目录下注册所有可用hooks。用户在使用时,需要在
package.json中定制化声明Git Hooks,譬如:
{
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,vue}": ["vue-cli-service lint", "git add"]
}
}这样,在执行 git commit 时,就会触发 pre-commit 钩子。
要注意的的一点,由于 yorkie 依赖 .git 目录,所以在安装 yorkie 之前,最好保证当前项目目录已经执行 git init 命令,创建了 .git 目录。
如果说,先安装了 yorkie,后执行了 git init。那么你可以手动执行 yorkie 的 bin/install.js 文件进行补救:
node "node_modules/yorkie/bin/install.js"另外 yorkie@2.0.0 与 pnpm 存在兼容性问题,因为在 yorkie 的源码中有如下设置:
const isInSubNodeModule = (depDir.match(/node_modules/g) || []).length > 1
if (isInSubNodeModule) {
return console.log(
"trying to install from sub 'node_module' directory,",
'skipping Git hooks installation'
)
}而当使用 pnpm 安装 yorkie 时,实际的 depDir 目录会是 /Users/xxx/projects/test-yorike/node_modules/.pnpm/yorkie@2.0.0/node_modules/yorkie(因为 pnpm 使用了文件短链接的缘故)。
这样就会导致上述逻辑拦截,从而跳过 Git Hooks 的安装。
解决办法是使用yorkie-pnpm。
实际上,yorkie-pnpm 是 yorkie 的 fork 项目,专门用于解决 yorkie 与 pnpm 的兼容性问题。
可见此处具体的PR。
1-2.husky
较新版本的husky 已经不推荐 autoinstall。
譬如笔者在测试中使用的版本是husky@^8.0.3。
新版本的 husky 使用方式有两种:
第一种是利用
npx husky-init第二种是手动安装
husky,然后配置Git Hooks。
详见安装husky
安装完成后,执行 git config -l 会发现 core.hookspath=.husky。
如果要卸载 husky 的话,执行:
npm uninstall husky && git config --unset core.hooksPath然后你可以根据实际需求,抉择是否删除 .husky 目录:
rm -rf .huskyhusky 根据 git 提供的 core.hooksPath 创建了 .husky 目录,不再依赖 .git 目录。
但由于映射关系的存在,同样需要先利用 git init 创建 .git 目录。
2.yorkie of vue-cli
yorkie 是 fork 自 husky,在安装时,会 autoinstall。
假设 vue-app-git 和 vue-app-not-git 都是利用 vue create 创建的项目。
二者的唯一区别是,vue-app-git 是在本机检测有 git 的情况下安装的,而 vue-app-not-git 则是在本机检测没有 git 的情况下安装的。
上述区别是通过更改全局包 @vue/cli-shared-utils 中的 hasGit 函数返回值实现的。
vue-app-git 和 vue-app-not-git 都是选择了 lint on commit,但实际执行,会发现:
vue-app-git的git commit会触发检测。vue-app-not-git的git commit则不会触发检测。
这是因为当 yorkie 在安装会自动执行,但在 vue-app-not-git 下没有找到 .git 目录,也就无法在 .git/hooks 下注入执行脚本。
3.Notes
3-1.prepare
在 scripts 下定义了 prepare 生命周期钩子。
但利用 yarn add yorkie -D 时,prepare 会触发,而 npm install yorkie --save-dev 并不会触发。
执行 npm install 会触发 prepare 生命周期钩子。
3-2.install & uninstall
在 scripts 下定义了 install 和 uninstall。
但为什么触发 install 和 uninstall 时,并没有打印 node bin/install.js 中的 console 呢?
答案是与 npm 版本相关。
测试了下,pnpm@7.33.6 在安装或者卸载包时,不会触发 install 或 uninstall 生命周期钩子。
因此 vue-app-git-pnpm 目录下的 git commit 不会触发 pre-commit 钩子。
4.NPM Life Cycle Scripts
查看 NPM 支持的生命周期钩子:life-cycle-scripts
5.Git Hooks
查看 Git 支持的钩子:Git Hooks