Git Hooks、Husky 和 lint-staged 在前端工程化中怎么配合?
简化版
Git Hooks 可以在提交、推送等阶段执行脚本;Husky 用来管理项目级 hooks;lint-staged 只对暂存区文件运行格式化和 lint。它们常配合做提交前质量门禁,但不能替代 CI,因为本地 hook 可能被跳过。
详细版
常见组合:
- pre-commit:运行 lint-staged,只检查本次改动文件。
- commit-msg:校验 commit message 规范。
- pre-push:可选跑轻量测试。
- CI:跑完整 lint、test、build。
为什么用 lint-staged:
- 全量 lint 在大项目里太慢。
- 只检查暂存文件能提高提交体验。
- 自动格式化后重新写回暂存区。
注意点:
- hook 要快,太慢会被开发者绕过。
- 本地 hook 可被
--no-verify跳过。 - CI 必须保留最终门禁。
- 不要在 pre-commit 里跑超重任务。
完整版教学
一、本地门禁解决的是“早发现”
CI 能挡住坏代码进主干,但如果每次都等 CI 才发现格式错误,反馈太晚。Git Hooks 把部分检查前移到提交时,让低级问题在本地就被修掉。它的目标不是替代 CI,而是降低 CI 红灯和 review 噪声。
Husky 的价值是把 hooks 配置进项目,让团队共享同一套提交规则。lint-staged 则让检查范围缩小到暂存文件,避免每次提交都扫完整仓库。
git commit
→ pre-commit
→ lint-staged 检查暂存文件
→ commit-msg 校验提交信息
→ 进入远端 CI 全量检查
二、lint-staged 为什么只看暂存区
开发者本地可能有很多未完成文件。如果提交只改了 2 个文件,却全量格式化 500 个文件,会引入巨大无关 diff。lint-staged 只处理 git add 的文件,符合“提交什么检查什么”的直觉。
数字例子:全仓库 ESLint 需要 90 秒,暂存 3 个文件只需要 2 秒。90 秒的 pre-commit 很快会逼开发者使用 --no-verify;2 秒的检查更容易被团队接受。
{
"lint-staged": {
"*.{js,ts,vue,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,md,json}": ["prettier --write"]
}
}
三、Husky 管的是 hook 分发
Git 原生 hooks 存在 .git/hooks,默认不随仓库提交。Husky 通过项目脚本把 hook 配置放进仓库,使团队成员安装依赖后自动拥有同样的 hook。这样规则不再靠口口相传。
不过安装脚本也要注意包管理器和 CI 环境。某些环境不需要安装 hooks,某些 monorepo 需要在根目录统一管理。工程化配置要服务团队,而不是变成“每台机器都要玄学修 hook”。
四、commit message 校验有什么意义
规范提交信息能让 changelog、版本发布、自动化分析更可靠。比如 Conventional Commits 中 feat: 表示功能,fix: 表示修复,BREAKING CHANGE 表示破坏性变更。工具可以据此生成发布日志。
| 类型 | 含义 | 示例 |
|---|---|---|
| feat | 新功能 | feat: add login page |
| fix | 修复 | fix: correct price display |
| docs | 文档 | docs: update usage |
| refactor | 重构 | refactor: split hooks |
这对组件库和多包发布尤其重要,因为版本和 changelog 经常依赖提交或 changeset 记录。
五、hook 不能承担太重任务
pre-commit 适合快任务:格式化、增量 lint、类型局部检查。全量测试、完整构建、端到端测试通常更适合 CI 或 pre-push。否则提交体验太慢,开发者会主动绕开 hook。
一个经验是 pre-commit 尽量控制在 5 到 10 秒内。超过 30 秒就要认真评估是否放错阶段。工程化不是越严格越好,而是在反馈速度和质量之间做平衡。
六、CI 是最终事实
本地 hooks 可以被跳过,也可能因为依赖没装、环境不同而失效。CI 才是合并前最终门禁。所有关键规则都应该在 CI 再跑一遍,尤其是 build、test、typecheck、安全扫描。
记忆钩子:本地 hook 是门口提醒,CI 是高速收费站;提醒可以漏,收费站不能撤。
七、常见误区与追问
- 误区:有 Husky 就不需要 CI 检查。 本地 hook 可被跳过,CI 必须保留最终门禁。
- 误区:pre-commit 越严格越好。 太慢会破坏体验,应把重任务放到 CI 或 pre-push。
- 误区:lint-staged 会检查全仓库。 它主要处理暂存区文件,适合增量质量控制。
- 追问:为什么格式化后还要重新 add? 格式化会修改文件,lint-staged 通常会把修改重新加入暂存区。
- 追问:commit-msg 校验有什么价值? 支持 changelog、语义化发布和提交历史可读性。
- 追问:如何防止 hook 环境不一致? 锁定 Node 和包管理器版本,并在 CI 中跑同样规则。
八、加强记忆
Git Hooks 这题用“本地快检,CI 终检”来记。Husky 负责分发 hooks,lint-staged 负责只检查暂存文件,commit-msg 负责提交规范;pre-commit 要快,CI 要全。本地体验和主干质量都照顾到,工程化才长久。