背景
在前端项目里,最常见的问题不是"代码跑不起来",而是"能跑,但有 lint warning/error,最后在 CI 或 Vercel 部署阶段失败"。
一个更稳妥的做法是把校验前置到 git commit:
- 本地提交前先过 ESLint
- 发现 warning/error 直接阻止提交
- 减少反复 push 后再回头修复的问题
这和 VSCode 有关系吗?
核心机制不是 VSCode,而是 Git Hook。
- 无论你是在 VSCode 点"提交",还是在终端执行
git commit - 只要仓库里配置了
pre-commithook - 就会触发同一套检查逻辑
所以本质是"仓库配置",不是"编辑器拦截"。
整体链路
提交时的执行链路通常是:
git commit- Git 读取
core.hooksPath(例如.husky/_) - 触发
.husky/pre-commit - 执行
npx lint-staged lint-staged仅对"已暂存文件"执行eslint --max-warnings=0- 若有 warning/error,命令返回非 0,Git 中止本次提交
为什么推荐 lint-staged
直接在 pre-commit 跑 eslint . 也能拦截,但效率较低:
- 每次提交都扫全量代码
- 速度慢,影响日常开发体验
lint-staged 的优势是:
- 只检查暂存文件
- 速度快
- 更适合日常频繁提交
标准配置(单仓库)
1. 安装依赖
bash
yarn add -D husky lint-staged
2. package.json 增加脚本和 lint-staged 配置
json
{
"scripts": {
"lint": "eslint .",
"prepare": "husky"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --max-warnings=0"
]
}
}
3. 初始化 Husky 并创建 pre-commit
bash
yarn prepare
新建 .husky/pre-commit:
sh
npx lint-staged
建议给脚本可执行权限:
chmod +x .husky/pre-commit
子目录前端项目(父目录才是 Git 根)
如果前端项目在子目录(例如 backend-admin/),而 Git 根在上一级,需要特别处理:
package.json 的 prepare
json
{
"scripts": {
"prepare": "cd .. && ./backend-admin/node_modules/.bin/husky backend-admin/.husky"
}
}
pre-commit(从 Git 根进入子项目执行)
.husky/pre-commit:
sh
cd backend-admin || exit 1
npx lint-staged
这样可以避免 husky 报 .git can't be found,并确保命令在正确目录执行。
常见坑与解决方案
1. 有 warning 也要阻止提交
必须使用:
bash
eslint --max-warnings=0
否则 warning 默认不会让命令失败。
2. lint-staged 中环境变量不生效
lint-staged 默认不是 shell 执行,写成 FOO=bar eslint ... 可能报 ENOENT。
可选方案:
- 用
cross-env包装 - 或改成脚本文件统一处理
3. Monorepo / 多项目目录误扫
建议:
- 在目标子项目目录放
package.json的lint-staged配置 pre-commit里cd到目标目录再执行
这样只校验该项目的暂存文件,不影响其他子项目。
4. Husky v9 提示旧模板弃用
Husky v9 不需要旧的 husky.sh 引入模板。
pre-commit 直接写:
sh
npx lint-staged
即可。
团队落地建议
- 在 README 或团队规范里写清楚"提交前拦截策略"。
- 把"warning 视同失败"作为统一标准,避免每人本地口径不一致。
- CI 仍保留 lint 检查,Hook 负责前置,CI 负责兜底。
- 新同学拉代码后执行一次依赖安装(会触发
prepare)。
结论
这套方案的核心不是 VSCode,而是 Git Hook。通过 Husky + lint-staged + eslint --max-warnings=0,可以把问题拦在提交前,显著减少"部署时才发现 lint 问题"的返工。
如果你的目标是"提交质量稳定 + 部署失败率下降",这套配置是性价比很高的基线方案。