在 Next.js 项目中驯服代码仓库猛兽:Husky + Lint-staged 预提交钩子全攻略

代码仓库有点像一座动物园:

  • 有些文件是乖巧的小兔子,推到 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 testnpm 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:大道本体,保持清净与秩序。

所以,别再担心队友往仓库里丢一堆"奇形怪状的缩进"。

有了这两位守门人,代码世界从此不再是野生动物园,而是井然有序的禅院。

相关推荐
Mintopia2 小时前
AIGC API 接口的性能优化:并发控制与缓存策略
前端·javascript·aigc
IT_陈寒3 小时前
SpringBoot 3.2新特性实战:这5个隐藏技巧让你的启动速度提升50%
前端·人工智能·后端
星哥说事3 小时前
国产开源文档神器:5 分钟搭建 AI 驱动 Wiki 系统,重新定义知识库管理
前端
degree5203 小时前
前端单元测试入门:使用 Vitest + Vue 测试组件逻辑与交互
前端
3Katrina3 小时前
一文解决面试中的跨域问题
前端
web3d5203 小时前
Three.js 角度单位介绍
javascript
阿白19553 小时前
JS基础知识——创建角色扮演游戏
前端
傻梦兽3 小时前
用 scheduler.yield() 让你的网页应用飞起来⚡
前端·javascript
然我3 小时前
搞定异步任务依赖:Promise.all 与拓扑排序的妙用
前端·javascript·算法