切换语言
切换主题

Next.js 工程化配置:ESLint + Prettier + Husky 一站式搭建

周五晚上的噩梦

还记得上周五晚上,我刚准备关电脑回家,突然看到 Slack 上技术负责人发来一条消息:“你的 PR 里格式问题太多了,能先整理一下再提交吗?“我点开 GitHub,满屏的红色 diff,全是因为有的地方用了双引号,有的地方缩进不一致。

老实讲,那种感觉特别无力。我明明记得提交前运行过 npm run lint 的啊,为什么还是出问题?更尴尬的是,团队里另一个同事也遇到了类似情况,他的代码逻辑完全没问题,就是格式和我的不一样,结果合并时产生了一堆无意义的冲突。

你有没有遇到过这种情况?代码写得好好的,却因为格式问题在 PR review 上来回折腾,浪费大家时间。我当时就在想:有没有一劳永逸的解决方案,让机器自动帮我们搞定这些琐事?

答案是有的:ESLint + Prettier + Husky 这套组合拳。

为什么需要这三个工具?

说实话,刚听到这三个名字的时候,我也觉得有点复杂。但用了一段时间后,真的回不去了。让我分别说说它们的价值。

ESLint:代码质量的守护者

很多人以为 ESLint 只是用来检查代码格式的,其实它更重要的作用是捕获潜在的代码问题

举个例子,Next.js 官方推荐使用 <Image> 组件而不是 HTML 的 <img> 标签,因为前者有自动优化功能。如果你不小心写了 <img>,ESLint 会立刻报错提醒你:

Error: Do not use <img>. Use Image from 'next/image' instead.

这种提醒在开发阶段就能避免性能陷阱,比等到上线后发现图片加载慢再优化要高效得多。

Next.js 15 默认启用了 ESLint,但你需要正确配置才能发挥它的最大价值。

Prettier:格式化的终极方案

ESLint 专注于代码逻辑和质量,Prettier 则专注于代码格式。两者分工明确,不应该混淆。

我们团队之前经常为格式问题争论:有人喜欢单引号,有人喜欢双引号;有人习惯缩进 2 个空格,有人习惯 4 个空格。每次 code review 都要讨论这些无关紧要的细节,真的很浪费时间。

配置 Prettier 后,这些问题彻底消失了。你只需要在项目开始时和团队成员一起定好规则(比如统一用单引号、缩进 2 空格),之后 Prettier 会自动格式化所有代码。配置一次,终身受益

Husky:自动化的关键

工具再好,如果要手动运行,总有人会忘记。

我自己就经历过好几次:本地开发时忘记运行 npm run lint,直接提交代码,结果 CI 流程失败,整个团队的部署都被阻塞了。那种尴尬感,真的不想再经历第二次。

Husky 的作用就是在你提交代码之前,自动运行检查。它会在 Git 的 pre-commit 阶段拦截你的提交,先运行 ESLint 和 Prettier,确保代码符合规范后才允许提交。

配合 lint-staged,Husky 只会检查你修改过的文件,而不是全项目扫描,所以速度非常快。你不用担心 pre-commit hook 拖慢开发节奏。

三者协同的威力

这三个工具组合起来的工作流程是这样的:

  1. ESLint 定义代码质量规则(比如不允许用 var,必须用 constlet
  2. Prettier 统一代码格式(比如所有字符串都用单引号)
  3. Husky 在提交前自动运行检查,确保没有人遗漏

团队受益是显而易见的:

  • PR review 时不再纠结格式问题,专注于业务逻辑
  • 代码合并冲突减少(因为格式统一)
  • CI 失败率降低(因为提交前已经检查过)

完整配置流程

好,下面进入实战环节。我会一步步带你配置这套工具链,尽量避免踩坑。

步骤 1:初始化 Next.js 项目

如果你已经有项目了,可以跳过这一步。如果是新项目,运行:

npx create-next-app@latest my-app
cd my-app

创建项目时,记得选择 TypeScriptESLint。Next.js 15 默认会帮你启用 ESLint,这省了不少事。

步骤 2:安装依赖

运行下面的命令(我用的是 pnpm,你也可以用 npm 或 yarn):

pnpm add -D eslint eslint-config-next prettier eslint-config-prettier husky lint-staged

这里简单解释一下每个包的作用:

  • eslint:ESLint 核心
  • eslint-config-next:Next.js 官方的 ESLint 配置(包含 Next.js 特有的规则)
  • prettier:Prettier 核心
  • eslint-config-prettier:关闭 ESLint 中与 Prettier 冲突的格式规则
  • husky:Git hooks 管理工具
  • lint-staged:只对暂存的文件运行检查

注意:不要安装 eslint-plugin-prettier。很多教程会推荐这个包,但它会让 Prettier 作为 ESLint 规则运行,导致性能问题。正确的做法是让 ESLint 和 Prettier 分开运行。

步骤 3:配置 ESLint

这一步是最容易踩坑的,尤其是 Next.js 15 升级到 ESLint 9 后,配置格式发生了变化。

使用 ESLint 9 的 Flat Config 格式(推荐)

在项目根目录创建 eslint.config.mjs

// eslint.config.mjs
import { FlatCompat } from '@eslint/eslintrc';
import nextPlugin from '@next/eslint-plugin-next';

const compat = new FlatCompat();

export default [
  ...compat.extends('next/core-web-vitals'),
  {
    plugins: {
      '@next/next': nextPlugin,
    },
    rules: {
      '@next/next/no-img-element': 'error',
      'react/no-unescaped-entities': 'off',
      // 这里可以添加你自己的规则
    },
  },
  {
    ignores: ['.next/', 'node_modules/', 'out/'],
  },
];

关键点

  • ESLint 9 不再使用 .eslintrc.json,而是用 flat config 格式(eslint.config.mjs
  • 如果你升级到 Next.js 15 后遇到 “The Next.js plugin was not detected” 错误,大概率是配置格式不对
  • Next.js 16 将移除 next lint 命令,所以提前适应新格式是明智的

降级方案(如果遇到兼容性问题)

如果你暂时不想折腾 flat config,可以设置环境变量降级到 ESLint 8 的配置格式:

ESLINT_USE_FLAT_CONFIG=false

然后继续使用 .eslintrc.json

{
  "extends": ["next/core-web-vitals", "prettier"],
  "rules": {
    "@next/next/no-img-element": "error"
  }
}

不过我建议还是尽早迁移到 flat config,毕竟这是未来的趋势。

步骤 4:配置 Prettier

在项目根目录创建 .prettierrc.json

{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "es5",
  "tabWidth": 2,
  "printWidth": 80,
  "arrowParens": "avoid"
}

这些配置是我个人比较喜欢的,你可以根据团队习惯调整:

  • singleQuote: true:我更喜欢单引号,看起来简洁
  • printWidth: 80:每行最多 80 个字符,适合并排显示多个编辑器窗口
  • trailingComma: 'es5':在对象和数组的最后一项加逗号,这样 Git diff 会更干净

再创建 .prettierignore,告诉 Prettier 忽略哪些文件:

.next
out
node_modules
public
*.lock

VSCode 集成(可选但推荐)

如果你用 VSCode,可以创建 .vscode/settings.json,实现保存时自动格式化:

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}

这样每次按 Ctrl + S 保存文件时,Prettier 会自动格式化代码。真的很爽。

步骤 5:配置 Husky + lint-staged

这一步是整个配置流程的精华,也是最能提升团队协作效率的部分。

初始化 Husky

运行:

pnpm dlx husky init

这个命令会自动创建 .husky/ 文件夹,并在 package.json 中添加 prepare 脚本:

{
  "scripts": {
    "prepare": "husky install"
  }
}

prepare 脚本的作用是确保团队成员在运行 pnpm install 时,自动安装 Husky hooks。这样新加入的同事不需要额外操作,克隆项目后直接就能享受到自动化检查的保护。

配置 pre-commit hook

编辑 .husky/pre-commit 文件:

pnpm lint-staged

就这么简单。每次你运行 git commit 时,Husky 会先执行 pnpm lint-staged

配置 lint-staged

在项目根目录创建 .lintstagedrc.mjs

export default {
  '*.{js,jsx,ts,tsx}': [
    'eslint --fix',
    'prettier --write',
  ],
  '*.{json,md,css}': [
    'prettier --write',
  ],
};

这段配置的意思是:

  • 对于 .js.jsx.ts.tsx 文件,先运行 eslint --fix(自动修复问题),再运行 prettier --write(格式化)
  • 对于 .json.md.css 文件,只运行 prettier --write

性能优化技巧

  1. 只检查暂存文件:lint-staged 会自动过滤出 git add 的文件,不会扫描整个项目
  2. 避免全局检查:千万不要在 pre-commit 中运行 pnpm lint(这会检查全项目,速度很慢)
  3. 跳过测试:pre-commit 只做格式检查和基础的代码质量检查,复杂的测试留给 CI
  4. 紧急提交时跳过:如果你确实需要跳过检查(比如紧急修复线上问题),可以用 git commit --no-verify

常见问题排查

Windows 环境下 Husky 不生效

如果你用 Windows,确保你的 Git 配置使用的是 Git Bash,而不是 CMD 或 PowerShell。另外检查 .husky/pre-commit 文件是否有执行权限:

chmod +x .husky/pre-commit

hook 执行太慢

如果 pre-commit hook 运行超过 10 秒,检查你的 lint-staged 配置,确保没有误配置全项目检查。正常情况下,只检查几个文件的 lint-staged 应该在 2-3 秒内完成。

验证配置

配置完成后,我们来验证一下是否生效。

测试步骤

  1. 随便修改一个文件,故意加入格式问题(比如把单引号改成双引号,或者删掉几个分号)
  2. 运行 git add .
  3. 运行 git commit -m "test"
  4. 观察终端输出

成功标志

如果配置正确,你会看到类似这样的输出:

✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...

然后打开你修改的文件,会发现格式问题已经被自动修复了。这就是自动化的魅力。

如果失败了

  • 检查 .husky/pre-commit 文件是否存在,内容是否正确
  • 检查 .lintstagedrc.mjs 文件是否在项目根目录
  • 尝试手动运行 pnpm lint-staged,看是否有报错信息

进阶配置

基础配置已经能满足大部分需求了,但如果你想要更严格的代码质量管理,可以考虑以下进阶配置。

添加 commitlint(规范提交信息)

除了代码格式,提交信息(commit message)的规范也很重要。commitlint 可以确保团队成员都遵循统一的提交信息格式(比如 Conventional Commits)。

安装依赖:

pnpm add -D @commitlint/cli @commitlint/config-conventional

创建 commitlint.config.mjs

export default {
  extends: ['@commitlint/config-conventional'],
};

添加 commit-msg hook:

echo "pnpm commitlint --edit \$1" > .husky/commit-msg

现在,如果你的提交信息不符合规范(比如 git commit -m "fix bug" 而不是 git commit -m "fix: bug"),提交会被拦截。

添加 TypeScript 类型检查

如果你希望提交前自动运行 TypeScript 类型检查,可以修改 .lintstagedrc.mjs

export default {
  '*.{ts,tsx}': [
    () => 'tsc --noEmit', // 类型检查
    'eslint --fix',
    'prettier --write',
  ],
  '*.{js,jsx}': [
    'eslint --fix',
    'prettier --write',
  ],
  '*.{json,md,css}': [
    'prettier --write',
  ],
};

注意tsc --noEmit 会检查整个项目的类型,速度比较慢。如果你的项目很大,可能会拖慢 pre-commit hook。我个人建议把类型检查留给 CI,pre-commit 只做格式和基础检查。

Monorepo 配置

如果你的项目是 Monorepo(比如用 pnpm workspace 或 Turborepo),配置稍微复杂一些:

  • 在根目录安装 Husky 和 lint-staged
  • 在每个 package 下创建独立的 .lintstagedrc.mjs
  • 避免配置”泄漏”到其他 package

具体配置可以参考 lint-staged 的官方文档。

常见问题与解决方案

配置过程中,你可能会遇到一些问题。这里总结几个常见的坑和解决方案。

Q1: ESLint 和 Prettier 规则冲突怎么办?

症状:ESLint 报错说某行代码格式不对,但 Prettier 格式化后又回到原样。

解决方案

确保你安装了 eslint-config-prettier,并且在 ESLint 配置中最后 extends prettier

export default [
  ...compat.extends('next/core-web-vitals'),
  ...compat.extends('prettier'), // 放在最后
];

eslint-config-prettier 会关闭 ESLint 中所有与 Prettier 冲突的格式规则,让 Prettier 专注于格式化,ESLint 专注于代码质量。

Q2: Next.js 15 升级后 ESLint 报错 “plugin not detected”

症状:运行 pnpm lint 时报错:

Error: The Next.js plugin was not detected in your ESLint configuration.

解决方案

这通常是因为 ESLint 9 的 flat config 格式不对。检查你的 eslint.config.mjs 是否正确导入了 @next/eslint-plugin-next

import nextPlugin from '@next/eslint-plugin-next';

export default [
  {
    plugins: {
      '@next/next': nextPlugin,
    },
  },
];

如果实在搞不定,可以暂时设置 ESLINT_USE_FLAT_CONFIG=false 降级到旧格式。

Q3: pre-commit hook 太慢怎么优化?

症状:每次提交都要等 10 秒以上,严重影响开发效率。

解决方案

  1. 确认 lint-staged 只检查暂存文件(正常情况下应该是自动的)
  2. 移除 pre-commit 中的测试脚本(测试应该在 CI 阶段运行)
  3. 如果项目很大,考虑只对 .ts.tsx 文件运行 ESLint,其他文件只运行 Prettier

Q4: 团队成员没有安装 Husky hooks

症状:新同事克隆项目后,提交代码时没有触发 pre-commit hook。

解决方案

确保 package.json 中有 prepare 脚本:

{
  "scripts": {
    "prepare": "husky install"
  }
}

告诉同事运行一次 pnpm install,Husky hooks 会自动安装。

Q5: Windows 环境下 Husky 不生效

症状:Windows 用户提交代码时,pre-commit hook 没有运行。

解决方案

  1. 确保 Git 配置使用的是 Git Bash(而不是 CMD)
  2. 检查 .husky/pre-commit 文件权限,尝试手动添加执行权限:
chmod +x .husky/pre-commit
  1. 如果还是不行,尝试重新初始化 Husky:
rm -rf .husky
pnpm dlx husky init

总结与最佳实践

配置这套工具链花了我大概半小时,但它给团队带来的价值是长期的。

核心收益

  • 代码质量提升:ESLint 在开发阶段就能捕获潜在问题,避免线上事故
  • 团队协作高效:统一的代码格式,减少无意义的 PR 争论和合并冲突
  • 自动化保障:Husky 确保每次提交都符合规范,再也不用担心忘记检查

最佳实践建议

  1. 渐进式配置:不要一开始就配置很严格的规则。先用默认配置跑一段时间,发现问题再逐步调整。
  2. 团队共识:Prettier 配置(比如单引号 vs 双引号)需要团队成员一起讨论决定,不要自己一个人定。
  3. 性能优先:pre-commit hook 只做必要的检查,复杂的测试留给 CI。
  4. 定期更新:关注 Next.js 和 ESLint 的版本变化,尤其是 Next.js 16 即将移除 next lint 命令。

下一步行动

如果你还没有在项目中配置这套工具链,我建议你现在就试试看。跟着这篇文章一步步操作,半小时就能搞定。

然后把配置分享给团队成员,统一大家的开发环境。

最后,根据团队的具体情况,调整 Prettier 和 ESLint 规则。记住,工具是为人服务的,不要被工具绑架。

个人经验

说实话,配置这套工具链刚开始确实会觉得麻烦,尤其是遇到 ESLint 9 的 flat config 迁移问题时,我也折腾了好一阵子。但用上之后真的回不去了。

现在我每次提交代码,完全不用担心格式问题,也不用担心忘记运行 lint。pre-commit hook 会自动帮我检查一切,那种安心感真的很棒。

团队的 PR review 效率也明显提升了。以前大家会在 PR 里讨论”这里应该用单引号还是双引号”,现在完全不会出现这种情况,因为 Prettier 早就统一好了。我们可以把时间花在讨论业务逻辑和架构设计上,而不是纠结格式细节。

这种自动化带来的效率提升,真的值得花这点时间配置。


希望这篇文章能帮到你。如果在配置过程中遇到问题,欢迎在评论区留言,我会尽力帮你解答。

祝你配置顺利!

12 分钟阅读 · 发布于: 2026年1月6日 · 修改于: 2026年1月22日

评论

使用 GitHub 账号登录后即可评论

相关文章