githooks 前端工程化实践

398 阅读4分钟

前言

Git 官网对 githooks 的解释为 Hooks used by Git,即 Git 使用的钩子。Hook(钩子) 是一种编程机制,是计算机程序设计术语,指通过拦截软件模块间的函数调用、消息传递、事件传递来修改或扩展操作系统、应用程序或其他软件组件的行为的各种技术,例如生命周期函数。在 Git 中分为客户端钩子和服务端钩子,客户端钩子被用户操作触发,例如 commit,服务端钩子被网络动作触发,例如 pushed

客户端常用 hook

1. pre-commit

commit 动作完成前触发此 hook,可以用此 hook 检查代码风格、代码规范,或者运行自动化测试。当返回非零值时 Git 会放弃本次提交,也可以使用 git commit --no-verify 忽略,跳过本次 hook 的执行。

2. prepare-commit-msg

commit 时需要输入 message 前会触发,可以用此 hook 来定制自己的 default message 信息。该 hook 接收一个包含提交信息的文件名的参数,当返回非零值时 Git 会放弃本次提交。

3. commit-msg

当用户输入 commit 的 message 后被触发,可以用此 hook 校验 message 的信息,比如格式是否符合规范等。该 hook 接收一个包含提交信息的文件名的参数,当返回非零值时 Git 会放弃本次提交。

4. post-commit

commit 动作完成后被触发,可以用此 hook 推送消息等。

服务端常用 hook

1. pre-receive

当服务端收到 push 动作之前会被执行。

2. post-receive

当服务端收到 push 动作并且已经完成的时候会被触发,可以用此 hook 来推送消息,比如发邮件,通知持续构建服务器等。

配置 githooks

githooks 存放在 .git/hooks 目录,没有配置 githooks 的仓库默认会有很多 .sample 结尾的示例文件,去掉 .sample 重命名文件可以使 hooks 生效。在我们手动配置 githooks 的过程中,需要在对应名字的 hook 文件中编写逻辑,并且 .git 文件夹不能上传到远程仓库,配置无法共享,需要在根目录创建新的文件夹存放 hooks 并配置给 git 运行,比较繁琐,所以使用 Husky 来更加方便的配置 githooks,参考 Husky 官网

以 vite 的 react-ts 模板为例

1. 创建项目 (记得初始化自己的git仓库)

yarn create vite my-app --template react-ts

2. 安装 husky

yarn add husky -D

3. 启用 hook

npx husky install

要在添加新的 hook 后自动启用,请编辑 package.json

npm pkg set scripts.prepare="husky install"

执行以上命令你将得到下边的内容,如果 npm 版本过低不支持此命令也可以手动填写。

// package.json 
{ 
    "scripts": { 
        "prepare": "husky install"
     } 
}

4. 创建一个 hook

要创建 hook 或者添加新命令,请使用husky add <file> [cmd](在此之前需要 husky install 获得 .husky 目录),例如创建一个 pre-commit hook:

npx husky add .husky/pre-commit ""

此时会创建一个执行逻辑为空的 pre-commit hook,可以根据需求添加不同的 [cmd] ,比如跑自动测试或者 eslint 校验。

5. 使用 eslint

安装 eslint

yarn add eslint -D

初始化 eslint 并生成配置文件

npx eslint --init

执行此命令后会进行初始化配置,根据自己项目的情况和使用习惯选择,例如:

✔ How would you like to use ESLint? · syntax
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · No / Yes
✔ Where does your code run? · browser
✔ What format do you want your config file to be in? · JavaScript

完成后会在项目根目录生成 .eslintrc 文件,可以在这里写具体规则,如果需要更加详细的配置可以参考 eslint 配置

6. 使用 lint-staged

lint-staged 为了实现每次提交只检查本次提交(暂存区)所修改的文件,避免在遗留项目中使用 eslint 时面对成千上万的 lint error。 多数人在项目中运用新工具都希望是渐进式的,而不是推倒重来。

安装 lint-staged

yarn add lint-staged -D

在 package.json 中配置,只检查暂存区的 .ts,.tsx 文件

// package.json
"lint-staged": {
    "*.{ts,tsx}": [
      "eslint --fix"
    ]
},

在 .husky/pre-commit 中关联 lint-staged 命令:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint-staged

到这里 pre-commit hook 已经配置完成,会在提交 commit 时通过 eslint 校验并修复可以修复的暂存区 .ts,.tsx 文件。

7. 规范提交日志

安装 commitlint 插件

yarn add @commitlint/cli @commitlint/config-conventional -D

初始化 commitlint 配置(注意根据CommonJS和ES选择生成 .js/.cjs 格式文件)

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.cjs

创建 commit-msg hook

npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

填写不符合规范的 message 时:

git commit -m "123"

⧗   input: 123
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

如果遇到使用 nvm 等工具管理 node 会遇到 command not found 的问题,需要在用户目录创建 .huskyrc 文件:

# ~/.huskyrc
# This loads nvm.sh and sets the correct PATH before running hook 
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

更多 githooks 及介绍请参考 Git 官网