在介绍 Prettier 的实际用法之前,必须先厘清一个经常被搞混的问题:Prettier 和 ESLint 到底什么关系?能不能只留一个?
这个混淆的根源在于 ESLint 在历史上确实承担了两件不同的事:代码质量检查和代码风格检查。早期 ESLint 规则库里混杂着两类规则——no-unused-vars(检查未使用的变量)是质量问题,quotes(检查引号类型)是风格问题。它们的性质完全不同,但因为都由同一个工具处理,开发者容易把它们混为一谈。
Prettier 出现后,业界逐渐形成了一个清晰的共识:代码质量检查和代码格式化是两件独立的事,应该由不同的工具分别负责。
用一个建筑领域的类比来解释:ESLint 是"结构工程师",负责检查建筑的安全性——承重墙有没有开洞、钢筋够不够粗、抗震设计是否达标。Prettier 是"室内装修规范",负责确保所有房间的门把手高度一致、开关位置统一、墙漆颜色协调。前者关系到建筑会不会塌,后者关系到建筑看起来舒不舒服。
两者都重要,但它们解决的是不同维度的问题。
ESLint 的典型能力:
no-unused-vars)no-unreachable)no-eval、no-implied-eval)eqeqeq 强制使用全等比较)no-use-before-define)Prettier 的典型能力:
两者的根本区别在于:ESLint 关心代码对不对,Prettier 关心代码好不好看。

有人可能会想:既然 Prettier 能统一格式,那 ESLint 里的风格规则都关掉,只用 Prettier 做格式化,用 ESLint 做质量检查不就行了?或者反过来,ESLint 的 auto-fix 已经能处理大部分格式问题,还要 Prettier 干什么?
第一种想法是正确的,这正是推荐的做法。但第二种想法有问题——ESLint 的格式化能力远远不如 Prettier。
ESLint 的 auto-fix 是基于规则驱动的。每条规则独立工作,各自修改自己负责的那部分格式。quotes 规则改引号,indent 规则改缩进,comma-dangle 规则改尾随逗号。它们之间缺乏全局视角的协调,有时候修了一条规则会跟另一条规则产生矛盾,或者对复杂嵌套结构的格式化处理不好。
Prettier 不存在这个问题。因为它通过 AST 到 Doc IR 的完整处理流程来决定最终格式,所有格式决策是在一个统一的布局算法中一起做出的,不存在规则间冲突。而且 Prettier 对多行拆分的处理(函数参数、链式调用、条件表达式等)远比 ESLint 任何单独的规则精细。
反过来,Prettier 也替代不了 ESLint。Prettier 不检查代码质量——它不会告诉你"这个变量声明了但没用到"或者"这里应该用全等而不是双等"。这些需要静态分析工具来做,Prettier 的架构设计中根本没有包含这个能力。
所以答案是:两者都需要,但各司其职。
实际项目中,ESLint 和 Prettier 的集成通过两个辅助包来实现。
这个包做的事情很简单:把 ESLint 中所有和格式相关的规则关掉。它提供一个 ESLint 配置集,你只需要在 ESLint 配置的 extends 数组里加上 "prettier" 就行。
// .eslintrc.js module.exports = { extends: [ "eslint:recommended", "plugin:react/recommended", "prettier" // 放在最后,关闭所有与 Prettier 冲突的规则 ], rules: { // 这里不需要再写任何格式相关规则 // Prettier 会处理所有格式问题 } };
把它放在 extends 数组的最后很关键,因为它需要覆盖前面配置集中的格式规则。ESLint 的 extends 是按顺序合并的,后面的配置会覆盖前面的。
这个包把 Prettier 作为一条 ESLint 规则来运行,让你可以在 ESLint 的输出中同时看到质量问题和格式问题。当你运行 eslint --fix 时,它也会同时调用 Prettier 格式化。
// .eslintrc.js module.exports = { extends: [ "eslint:recommended", "prettier" ], plugins: ["prettier"], rules: { "prettier/prettier": "error" } };
不过要注意:eslint-plugin-prettier 会增加一些性能开销(因为 ESLint 和 Prettier 各解析了一次代码),而且对于大项目来说,运行两次解析器的延迟比较明显。在 CI 环境中,更高效的做法是让 Prettier 和 ESLint 分别运行,而不是通过插件串联。
有几个常见的集成误区需要避免。
用 ESLint 规则代替 Prettier 的配置项。比如看到 Prettier 的 singleQuote: true,就在 ESLint 里配 quotes: ["error", "single"]。这是多余的,因为 Prettier 已经会在运行时统一格式,ESLint 的这条规则除了增加检查时间之外不产生额外价值。而且如果你某次忘了运行 Prettier,ESLint 会报格式错误,但这个错误 Prettier 本来就能自动修,让 ESLint 报它纯属浪费信息带宽。
只装 eslint-plugin-prettier 不装 eslint-config-prettier。这样 ESLint 的格式规则和 Prettier 的格式决策可能会冲突——ESLint 报告"引号类型不对",但 Prettier 确实就是这么处理的。结果就是 lint 输出里充斥着无效的格式警告。
在 git pre-commit 里只跑 ESLint 不跑 Prettier。如果你的 ESLint 没有集成 Prettier,pre-commit 只检查质量但不格式化,那格式问题仍然会流入代码库。正确的做法是在 pre-commit 里同时跑 prettier --write 和 eslint。
当你在配置项目时,拿不准某条规则应该归 ESLint 还是归 Prettier,可以用这个简单标准:这条规则只影响代码的外观(空格、换行、引号、分号等),还是影响代码的运行行为或正确性? 如果只影响外观,归 Prettier;如果影响正确性或可能导致 bug,归 ESLint。
举个例子:
no-console:ESLint。这是关于"代码里应不应该有 console 语句"的质量判断。arrow-parens:Prettier。这是关于"箭头函数单个参数要不要加括号"的格式偏好。no-mutable-exports:ESLint。可变的导出可能导致难以追踪的 bug。object-curly-newline:Prettier。对象字面量的花括号换不换行纯粹是格式问题。这个判断标准虽然简单,但在实践中几乎不会产生歧义。