代码仓库有点像一座动物园:
- 有些文件是乖巧的小兔子,推到 Git 上一点问题也没有。
- 有些代码却是脾气暴躁的鬣狗,容易咬人(比如没跑 lint 的不规范代码、没跑格式化的奇怪缩进)。
于是我们需要两位守门人:
- Husky:帮我们在 Git "大门"处加个拦截器。
- Lint-staged:像个"行李检查员",只检查你这次真的要带走的文件,而不是把整个仓库都翻个底朝天。
下面就让我们以一名既懂操作系统底层调度原理,又懂人类幽默的"计算机科学家"的身份,一步步拆解 Next.js 项目的预提交钩子建设。
一、为什么要有预提交钩子?
操作系统里有个概念叫 中断机制 :当设备发出请求,CPU 会打断当前进程插队处理。
Git 的 pre-commit hook 就是一种"开发者自定义中断",你想要提交?不好意思,先让我检查一下你交的作业是不是合格的。
没有钩子时:
- 任何人都能
git commit -m "乱七八糟"
,代码可能直接污染主分支。
有了钩子后:
- 提交会像超市出门前的监控门:不合规的提交,就会"滴滴"报警,打脸式阻止提交。
二、Husky 的登场:Git 的钩子管理员
安装 Husky
在 Next.js 项目根目录执行:
css
npm install husky --save-dev
npx husky install
在 package.json
里加一行,确保安装依赖时 Husky 自动初始化:
json
{
"scripts": {
"prepare": "husky install"
}
}
运行后,你会看到仓库里出现一个 .husky
文件夹。
这就是"守门狗的犬舍"。
添加预提交钩子
sql
npx husky add .husky/pre-commit "npm test"
这会生成 .husky/pre-commit
文件。里面写着:
bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm test
效果:提交前必须过测试。代码写得烂?抱歉,狗咬你,不给过。
三、Lint-staged:只拦截你的"行李"
单纯跑 npm test
或 npm run lint
太粗暴了,每次提交都要检查整个仓库文件,就像过安检要把整个图书馆的书都翻一遍。
这不科学。
于是有了 lint-staged:
- lint:检查代码质量。
- staged:只检查已经加入 Git 暂存区的文件。
这就是底层"调度"的精妙之处:像操作系统的调度器一样,只挑选需要运行的进程,而不是全盘扫描。
安装
css
npm install lint-staged --save-dev
配置 lint-staged
在 package.json
中加入:
json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md,css}": [
"prettier --write"
]
}
}
表示:
- 你改的 JS/TS 文件必须跑一次 eslint,并自动格式化。
- 你改的 JSON、Markdown、CSS 也要乖乖美化排版。
将 lint-staged 接到 Husky
修改 .husky/pre-commit
文件:
bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
这样一来,预提交流程就是:
- Husky 截胡。
- lint-staged 只检查你这次提交的行李。
- 不合规范?对不起,代码留堂。
四、Next.js 环境下的特别提醒
Next.js 有些文件是自动生成的,比如 .next/
目录。我们根本不需要它被检查。
所以 .eslintignore
和 .prettierignore
要记得配置:
lua
.next/
node_modules/
这样 Husky 和 lint-staged 就不会被迫"翻垃圾桶"。
五、一个小小的 JS 栗子:模拟钩子检查
我们甚至可以手写一个"假检查器",理解它的核心机制。
javascript
// fakePreCommit.js
const { execSync } = require("child_process");
try {
// 1. 获取暂存的文件
const files = execSync("git diff --cached --name-only", {
encoding: "utf-8",
})
.split("\n")
.filter(Boolean);
// 2. 模拟 lint
files.forEach((file) => {
if (file.endsWith(".js")) {
console.log(`检查 ${file} ...`);
// 假装发现问题
if (file.includes("bad")) {
throw new Error(`${file} 不合法!`);
}
}
});
console.log("检查通过,可以提交 🎉");
} catch (err) {
console.error("提交失败:", err.message);
process.exit(1);
}
这段小剧本告诉我们:钩子本质就是一段在提交前被执行的脚本。Husky 和 lint-staged 只是帮我们把这个流程标准化。
六、结语:仓库的江湖规矩
用上 Husky + Lint-staged 后,仓库从混乱无章的"江湖帮派",变成了有门槛的"修行道场":
- Husky:打门的和尚,谁想进来都要验身。
- Lint-staged:守门的师兄,不翻你所有行李,只看你这次带的。
- Next.js:大道本体,保持清净与秩序。
所以,别再担心队友往仓库里丢一堆"奇形怪状的缩进"。
有了这两位守门人,代码世界从此不再是野生动物园,而是井然有序的禅院。