上一节讲了代码格式化和静态检查,但工具再强大,如果开发团队不遵守,依然形同虚设。最可靠的方案是把规则嵌入到代码提交流程中,让不规范的代码根本进不了仓库。Husky、lint-staged 和 commitlint 就是为此而生的“提交门禁”工具。
23.3.1 三者分工
- Husky:在 Git 钩子(hook)执行自定义命令,比如在
pre-commit时运行检查,在commit-msg时校验提交信息。 - lint-staged:只对 Git 暂存区中的文件执行检查,避免每次提交都扫描整个项目,极大提升检查速度。
- commitlint:校验 git commit message 是否符合约定的规范,确保提交历史可读、可追溯。
三者的协作流程通常是:
开发者执行
git commit→ Husky 触发pre-commit钩子 → lint-staged 对暂存文件执行 ESLint/Prettier 检查 → 检查通过后进入commit-msg钩子 → commitlint 校验提交信息格式 → 全部通过后提交成功。
23.3.2 配置实战
以 npm 项目为例,假设项目已经安装了 ESLint 和 Prettier。
1. 安装依赖
npm install --save-dev husky lint-staged @commitlint/cli @commitlint/config-conventional
2. 初始化 Husky
如果使用的是 Husky v9+:
npx husky init
这会在项目根目录创建 .husky/ 目录,并自动添加 pre-commit 钩子文件。如果没有自动创建,可以手动添加:
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg "npx --no -- commitlint --edit \$1"
注意:
\$1是传递给钩子脚本的 commit message 临时文件路径,必须原样保留。
3. 配置 lint-staged
在 package.json 或单独的 lint-staged.config.js 中定义规则:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,scss,less,md,json}": ["prettier --write"]
}
}
含义:对暂存区中匹配的文件,先运行 ESLint 自动修复,再用 Prettier 格式化。
4. 配置 commitlint
在项目根目录创建 commitlint.config.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
// 自定义规则,例如限制 header 最大长度
'header-max-length': [2, 'always', 72],
},
};
这套“conventional”规范源自 Angular 提交规范,格式为:
<type>(<scope>): <short summary>
常用 type 包括:
feat:新功能fix:修复 bugdocs:文档变更style:代码格式(不影响功能)refactor:重构test:添加或修改测试chore:构建或辅助工具的变动
示例:feat(auth): add login with JWT
23.3.3 实际效果
配置完成后,开发者的体验是这样的:
$ git add .
$ git commit -m "fixed bug"
- 第一步,Husky 触发
pre-commit,lint-staged 自动对暂存文件执行 ESLint 和 Prettier。如果有问题,会自动修复或报错退出,阻止提交。 - 如果 lint-staged 通过,进入
commit-msg钩子,commitlint 检查提交信息格式。"fixed bug"因缺少type:前缀被视为非法,提交会被拒绝,并给出错误提示。 - 开发者需修改提交信息为
fix: fix user login error,重新提交才能成功。
23.3.4 这样做的实际价值
- 防止漏网之鱼:即使开发者忘记在本地运行 lint,代码在提交那一刻也会被强制检查,确保进入仓库的代码都是格式整洁、通过静态分析的。
- 保障提交历史可读:统一的提交格式让
git log清晰明了,自动生成 CHANGELOG 和版本管理都变得更可靠。 - 提升团队协作效率:新人入职后只需配置好本地的 Git 钩子(或依赖团队脚手架),无需记住所有检查命令,工具会自动把关。
- 只检需检查的文件:lint-staged 只扫描暂存区文件,避免了全量检查的时间开销,让提交过程依然快速。
23.3.5 常见问题与解决
1. 跳过钩子怎么办?
Git 允许用 --no-verify 强制跳过钩子:
git commit -m "emergency fix" --no-verify
原则上不能完全杜绝这种行为,但可以通过 CI/CD 在远端再做一次相同的检查。如果团队成员普遍依赖跳过,说明本地钩子配置体验不佳(如速度太慢),需要优化规则。
2. lint-staged 执行失败但代码已被格式化?
lint-staged 会优先执行 --fix,修复后的文件会被重新添加回暂存区。如果 ESLint 报告了无法自动修复的错误(如未使用的变量禁止删除),lint-staged 会返回非零退出码,阻止提交。这是预期行为,开发者需要手动修复后重新提交。
3. Windows 兼容问题
Husky 在不同操作系统下需要确保 shell 脚本可执行,通常通过 Git Bash 或 WSL 解决。使用 Husky v9+ 默认会处理好跨平台问题。如果遇到“权限不足”错误,可以尝试:
chmod +x .husky/pre-commit
23.3.6 小结
Husky + lint-staged + commitlint 组合是当前前端工程化中最主流的提交门禁方案。它们不需要昂贵的 CI 资源,在开发者本地就能完成最基本的代码质量把关,与 ESLint、Prettier 形成完整的“写 → 检 → 修 → 拦”闭环。善用这套工具,等于给项目团队加了一道低成本、高回报的质量防线。