(1). Husky安装hooks的原理:
node husky install
// 最终执行./lib/installer/bin中的脚本
// 而hooks的建立逻辑在./lib/installer/hooks.js中
(2). husky核心源码解读:
# Created by Husky v4.2.5 (https://github.com/typicode/husky#readme)
# At: 2020/8/3 上午11:25:21
# From: ... (https://github.com/typicode/husky#readme)
debug () {
if [ "$HUSKY_DEBUG" = "true" ] || [ "$HUSKY_DEBUG" = "1" ]; then
echo "husky:debug $1"
fi
}
command_exists () {
command -v "$1" >/dev/null 2>&1
}
// 做用就是用本地的husky-run指令执行hook
run_command () {
if command_exists "$1"; then
"$@" husky-run $hookName "$gitParams"
exitCode="$?"
debug "$* husky-run exited with $exitCode exit code"
if [ $exitCode -eq 127 ]; then
echo "Can't find Husky, skipping $hookName hook"
echo "You can reinstall it using 'npm install husky --save-dev' or delete this hook"
else
exit $exitCode
fi
else
echo "Can't find $1 in PATH: $PATH"
echo "Skipping $hookName hook"
exit 0
fi
}
// 经过grep指令判断各个配置文件中是否存在pre-commit
hookIsDefined () {
grep -qs $hookName \
package.json \
.huskyrc \
.huskyrc.json \
.huskyrc.yaml \
.huskyrc.yml
}
huskyVersion="4.2.5"
gitParams="$*"
// 获取当前脚本的名称,如:pre-commit
// 后面的指令匹配都是围绕这个名称,后面内容中的hookName都会以pre-commit为例
hookName="$(basename "$0")"
debug "husky v$huskyVersion - $hookName"
# Skip if HUSKY_SKIP_HOOKS is set
if [ "$HUSKY_SKIP_HOOKS" = "true" ] || [ "$HUSKY_SKIP_HOOKS" = "1" ]; then
debug "HUSKY_SKIP_HOOKS is set to $HUSKY_SKIP_HOOKS, skipping hook"
exit 0
fi
# Source user var and change directory
. "$(dirname "$0")/husky.local.sh"
debug "Current working directory is $(pwd)"
# Skip fast if hookName is not defined
# Don't skip if .huskyrc.js or .huskyrc.config.js are used as the heuristic could
# fail due to the dynamic aspect of JS. For example:
# `"pre-" + "commit"` or `require('./config/hooks')`)
if [ ! -f .huskyrc.js ] && [ ! -f husky.config.js ] && ! hookIsDefined; then
debug "$hookName config not found, skipping hook"
exit 0
fi
# Source user ~/.huskyrc
if [ -f ~/.huskyrc ]; then
debug "source ~/.huskyrc"
. ~/.huskyrc
fi
# Set HUSKY_GIT_STDIN from stdin
case $hookName in
"pre-push"|"post-rewrite")
export HUSKY_GIT_STDIN="$(cat)";;
esac
# Windows 10, Git Bash and Yarn 1 installer
if command_exists winpty && test -t 1; then
exec < /dev/tty
fi
# Run husky-run with the package manager used to install Husky
case $packageManager in
"npm") run_command npx --no-install;;
"npminstall") run_command npx --no-install;;
"pnpm") run_command pnpx --no-install;;
"yarn") run_command yarn run --silent;;
*) echo "Unknown package manager: $packageManager"; exit 0;;
esac
注:
- run_command函数,用做本地的husky-run指令执行hook:
- 如: "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "**/*.js": "eslint" // 执行eslint }
(3). 总结:
- 安装时建立hooks
- 提交时从配置文件中(package.json、.huskyrc、.huskyrc.json)读取相应的hook配置
- 执行配置中的指令/脚本