写代码这件事,换个角度看,从来不是一个人的单打独斗。哪怕是个人项目,过几个月回头看自己写的代码,如果没有规范,大概率也会骂一句“这写的什么鬼”。在团队协作里,这种情况更常见:有人习惯用双引号,有人死磕单引号;有人写分号,有人觉得那是累赘;还有人把逻辑写得像意大利面条一样绕。这时候,前端工程化这套“组合拳”就派上用场了。
很多新手会问,为什么不能只用一个工具?咱们来拆解一下这三个工具各自的“岗位职责”。
ESLint 是代码的“质量检查员”。它负责找茬,哦不,是找错误。比如你定义了一个变量却没用,或者在一个条件判断里写了恒为真的表达式,或者用了 var 这种过时的声明方式,ESLint 会毫不留情地给你标红。它关注的是代码逻辑是否正确、是否存在潜在 Bug。截至目前的最新版本 ESLint v9.15.0 (2024年11月),它已经成为了前端静态分析的标配。
Prettier 则是“强迫症式”的“美容师”。它不管你代码写得好不好,只管你代码长得好不好看。缩进是 2 格还是 4 格?尾逗号要不要加?换行在哪里换?Prettier 的态度非常 opinionated(自以为是),意思就是:别废话,按我的来。最新版 Prettier v3.4.1 (2024年10月) 支持几乎所有主流的前端语言,包括 JS/TS/CSS/JSON 等,它能移除你所有的原始样式,然后按照统一标准重新输出。
那为什么还要加个 Husky?这就好比你在路口立了个牌子说“请红灯停”,但总有人闯。Husky 就是那个电子警察,它利用 Git Hooks 机制,在你执行 git commit 的那一刻,强制检查你的代码。如果不符合规范,直接拒绝提交。现在 Husky v9.1.7 (2024年10月) 非常轻量且零依赖,用起来很顺手。
很多刚入行的同学容易避雷经验,觉得装一个就够了。其实 ESLint 和 Prettier 虽然偶尔会“打架”,但它们的关注点完全不同。
undefined 的坑,或者用了未定义的变量。git push,大家的代码依然没法统一。既然 ESLint 也管格式(比如缩进、空格),Prettier 也管格式,那它们肯定会冲突。解决办法就是引入 eslint-config-prettier。这个包的作用是关闭 ESLint 中所有与 Prettier 冲突的规则,让 Prettier 全权接管格式化。
可以这么理解,就是告诉 ESLint:“兄弟,格式化这块你别管了,交给 Prettier 吧,你专心抓逻辑错误就行。”
现在的趋势是,工具链在向原生语言(Rust/Go)迁移,比如新兴的 Biome 试图挑战传统组合。但在 2024 年,ESLint + Prettier 依然是最稳妥、生态最丰富的选择,特别是当你面对复杂的遗留系统重构或者大型开源项目时,这套组合的成熟度是无敌的。
---
如果你还在用 .eslintrc.js 或者 .eslintrc.json,那你真的有点落伍了。2024 年的今天,ESLint v9 已经默认抛弃了传统的“层级查找”配置模式,全面拥抱 Flat Config。
简单来说,以前 ESLint 会在你项目的每一个目录里找 .eslintrc,如果找不到就往父级找,效率低且容易出 Bug。现在的 Flat Config 就是一个文件:eslint.config.js(或者 .mjs)。这个文件导出一个数组,所有的配置都在这里,清晰明了,性能还更好。
咱们先安装必要的依赖。确保你用的 Node 版本不要太老。
注意,这里我们安装的是 ESLint v9.15.0(2024年11月最新版)和 Prettier v3.4.1。
现在,在项目根目录创建 eslint.config.js。这是核心步骤,也是很多人容易避雷经验的地方。
Prettier 的配置相对简单,创建一个 .prettierrc 文件。
你可能会看到有些教程让你装 eslint-plugin-prettier 把 Prettier 当 ESLint 规则跑。但在 2024 年,更推荐的做法是用 eslint-config-prettier。
核心要点:eslint-config-prettier 的作用是“关灯”。它把 ESLint 里那些管格式的灯关掉,这样 Prettier 跑起来就不会被 ESLint 干扰。
在 package.json 里加上运行脚本:
如果你是从旧项目升级上来的,可能会发现很多插件不支持 Flat Config。这时候你可以尝试在 eslint.config.js 里用 FlatCompat 来兼容旧插件,但这通常是下策。
我的建议是:如果是新项目,直接上 Flat Config。如果是老项目,先别急着升 ESLint v9,先用 v8 过渡,或者看看你的核心插件是否已经支持了 eslint.config.js。另外,Flat Config 里没有 extends 这种字符串数组了,而是直接导入对象,这种“配置即代码”的方式虽然刚开始不习惯,但确实更强大。
---
代码规范配好了,但怎么保证队友提交代码时一定会跑?靠自觉是不行的,必须上技术手段。这就是 Husky 和 lint-staged 登场的时候了。
Husky 负责“拦截”,lint-staged 负责“精准打击”。
其实,如果你每次提交都全量检查整个项目的代码,那速度慢得你会想砸电脑。特别是老项目,几万行代码,全跑一遍 Lint,光等就要几分钟。lint-staged 的意思就是:只检查你这次 git add 添加到暂存区(staged)的文件。这样速度快,反馈也及时。
咱们先把这两个工具装上。注意 Husky 现在是 v9.1.7 (2024年10月),它的初始化方式跟以前不一样了。
运行 npx husky init 后,你会发现项目根目录多了个 .husky 文件夹,里面有个 pre-commit 文件。
打开 .husky/pre-commit 文件,把里面的 npm test 改成运行 lint-staged。
接下来,我们需要在 package.json 里告诉 lint-staged 该对哪些文件做什么操作。
这个配置的意思是:当你试图提交 JS/TS 文件时,先跑 eslint --fix 自动修复,再跑 prettier --write 格式化;如果是样式或文档文件,只跑 Prettier。
现在你可以试试看效果了。
git add .git commit -m "test: check husky"如果一切正常,你会看到 Husky 触发了 lint-staged,然后它开始检查文件。如果代码有逻辑错误(ESLint 报错),或者格式不对,提交会被直接终止。
在 Windows 上用 Husky 有时候会遇到脚本执行权限或者路径问题。
实际案例经验:确保你的 pre-commit 文件第一行是 #!/usr/bin/env sh,并且在 Windows 上安装 Git 时选择了“Use Git and optional Unix tools from the Command Prompt”,这样 sh 命令才能找到。
另外,很多团队会纠结 lint-staged 里该先跑 ESLint 还是先跑 Prettier。其实无所谓,因为 eslint-config-prettier 已经关掉了冲突规则,谁先谁后都不打架。但为了保证逻辑错误优先拦截,建议先跑 eslint --fix,如果 ESLint 崩了,Prettier 就不用跑了,省点时间。
随着 Monorepo 架构的流行,在大型仓库里配置 Husky 也是个技术活。现在流行在根目录配置,利用 lint-staged 的过滤能力,只检查改动包里的文件,这样既保证了规范,又不会拖慢整个 CI/CD 流水线的速度。
可以这么理解,当你从单仓库切换到 Monorepo(比如用 pnpm workspace 或者 Turborepo)的时候,你会发现原来的 ESLint 和 Prettier 配置有点不够用了。如果每个 package 都单独搞一套配置,维护起来简直是噩梦,版本一更新,改起来能让你怀疑人生。所以,咱们得搞一套“基地+哨所”的策略。
核心思路就是:共享基础配置,局部差异化覆盖。
在 Monorepo 的根目录,我们通常会有一个基础的 eslint.config.js(注意,咱们现在用的是 ESLint v9.15.0,默认就是 Flat Config 了,别再搞 .eslintrc 那一套了)。然后,在各个子 package 里,我们只需要去继承和微调。
这里有个很骚的操作,因为 Flat Config 本质上就是一个 JavaScript 数组,我们可以直接 import 根目录的配置,然后利用数组的展开运算符 ... 来合并。
假设你有这样一个结构:
packages/client (前端应用)packages/server (后端逻辑)packages/shared (公共工具)根目录配置 (eslint.config.js):
这是咱们的大本营,放那些通用的规则,比如禁止 console.log(生产环境),或者强制使用 const。
子 Package 配置 (packages/client/eslint.config.js):
客户端可能需要浏览器环境的全局变量,或者 React 的规则。这时候咱们直接导入根配置,然后追加。
这可是个老生常谈的话题了。换个角度看,ESLint 管的是代码逻辑对不对(比如禁止未使用的变量),Prettier 管的是代码长得好不好看(比如该不该加分号)。但是,有些规则是重叠的,比如换行、引号、空格。
值得留意的是,在 2024 年的今天,如果你用的是 ESLint v9 和 Prettier v3.4.1,解决冲突的方式非常直接。
eslint-config-prettier:这个包的作用是关闭 ESLint 里那些跟 Prettier 冲突的格式规则。📌 要点提醒:千万别再同时用 eslint-plugin-prettier 和 eslint-config-prettier 了,那是老黄历。eslint-plugin-prettier 是把 Prettier 当 ESLint 规则跑,性能差,而且报出来的错误是格式化错误,很烦人。现在的最佳实践是:让 ESLint 只管逻辑,Prettier 只管格式,用 eslint-config-prettier 让他俩井水不犯河水。
如果你在 Monorepo 里遇到格式冲突,检查一下是不是某个子包的配置里忘了加 prettier。有时候为了省事,我会在根目录的 package.json 里强制所有 package 共享同一个 prettier 配置:
---
咱们做前端的,最怕的就是这种大版本升级。ESLint v9.15.0(2024年11月发布)带来了一个巨大的变化:Flat Config (eslint.config.js) 成为了默认选项。如果你还在用 .eslintrc.json,ESLint 会给你抛警告,甚至直接罢工。
我最近给公司项目做迁移,踩了不少坑,这里给大伙儿排个雷。
1. 配置文件的巨变
以前我们是写对象,现在要写数组。以前有 env,现在得在 languageOptions 里搞 globals。
以前:
现在(Flat Config):
2. 插件导入方式的改变
这是最坑的地方。以前插件名是字符串 "react",现在得 import 进来当对象用。
如果你装了 eslint-plugin-react,以前是 plugins: ['react'],现在得这么写:
3. 忽略文件的处理
以前 .eslintignore 很好用,现在 Flat Config 里推荐在配置数组里加一个对象专门处理忽略。
⚡ 效率提示:如果你还没迁移,别硬刚。直接用官方提供的迁移工具:npx @eslint/migrate-config .eslintrc.json。它能帮你自动转成 eslint.config.js,虽然不一定完美,但能省 80% 的力气。
聊到 2024-2026 年的趋势,就不得不提 Biome。这玩意儿是用 Rust 写的,号称是 ESLint + Prettier + 更多工具的一站式替代品。
可以这么理解,如果你受够了 npm install 几百个包,受够了 ESLint 启动慢,Biome 确实香。
但是,作为一个有 5 年经验的工程师,我得泼点冷水。
我的看法:
对于新项目,特别是中小型项目或纯工具库,直接上 Biome 是完全没问题的,体验极佳。
对于大型 Monorepo 或遗留系统,还是老老实实守着 ESLint v9 + Prettier v3 吧。毕竟稳定性第一,而且 eslint-config-prettier (最新版依然坚挺) 这种组合久经沙场,出了问题好排查。
现在的趋势是,传统的 JS 工具链都在向原生语言迁移(比如 Ruff 之于 Python),前端这边 Biome 和 Oxc 势头很猛。但 ESLint 毕竟是基石,短期(2-3年内)内地位还是很难被撼动的。咱们作为开发者,保持关注,但没必要盲目追新去重构现有项目的基建。