如果你所在的团队还在为代码格式争论比如“这里怎么不加空格”“字符串到底用单引号还是双引号”“这个 PR 为什么改了一堆无关行”那我强烈建议你认真看看这篇文章。Prettier 是当前前端社区使用最广泛的代码格式化工具核心思想就是四个字别争了按我的来。它最大的价值不在于把代码格式化得多漂亮而在于把“代码风格讨论”从 code review 中彻底移除让开发者把精力真正留给逻辑和架构。这篇文章会围绕 Prettier 的配置展开拆解核心配置项、配置文件组织方式、团队落地最佳实践以及我在真实项目里踩过的坑、排过的错适合刚接触 Prettier 的新手也适合正在优化团队格式化流程的资深工程师。1. 为什么团队最终都选了 Prettier1.1 它解决的是“吵架问题”代码风格统一这件事几乎所有团队都经历过一个尴尬循环入职第一天看前辈的代码觉得“这也太乱了吧”于是自己写的时候按自己习惯来然后 code review 时被指出“这里要加空格”“那里该换行”。这类评论一多真正重要的逻辑问题反而被淹没了。Prettier 解决的正是这个高频又低价值的问题。我第一次在团队里引入 Prettier是在一个十几个人的前端组。当时最明显的两个争议点分号加不加、字符串用单引号还是双引号。这两个问题在 GitHub 的 PR 里反复出现谁也说服不了谁。后来我们做的决定很简单所有人把格式化统一交给 Prettier代码评审里不再讨论任何“格式”问题。这一条规则写进团队规范之后PR 里的格式争论直接归零效率提升非常明显。Prettier 的定位是一个“格式化工具”核心能力是读取代码文件解析成抽象语法树AST然后按照内置规则重新打印出来。这意味着它不像传统的字符串替换类工具那样只能在局部做修补而是从结构上重排代码所以无论代码原始写成什么样格式化结果都高度一致。这也是为什么它比早期那些代码美化工具更可靠、更受社区欢迎。1.2 Prettier 的“固执”是设计不是 Bug很多人第一次用 Prettier 都会吐槽我只想改一个引号风格它为什么把我的代码整个重排了这可能确实是 Prettier 设计上的“有意为之”。Prettier 官方对自己的定位就是“An opinionated code formatter”翻译过来大概是“一个有主见的代码格式化工具”。这里展开说一下这个设计。Prettier 团队刻意把配置项控制得很少而且每一项都给出默认值。它的核心观点是代码格式的一致性比任何单一格式的美观都重要。哪怕某个换行在特定场景下看起来不那么完美只要全仓库统一它带来的可读性收益就远大于局部美感的损失。这就引出一个常见误区大家总是想给 Prettier 加配置、加规则让它“更符合我们的口味”。我自己早期也犯过这个错后来发现真正应该做的是少改默认值。配置项越少团队成员越不需要花精力去记规则格式化行为也越好预测。把这件事和 ESLint 对比就很清楚ESLint 是“规则引擎”管代码质量Prettier 是“排版引擎”管代码长什么样。如果每个团队都想定制一百条 ESLint 规则然后把这种思路搬到 Prettier 上最后一定会变成另一场争论。2. 核心配置项逐项拆解2.1 决定代码“形状”的三个参数printWidth、tabWidth、useTabs 这三个参数从宏观上决定代码长什么样先处理它们。printWidth默认 80表示行宽达到 80 时 Prettier 会尽量换行。要注意“尽量”这个词不是超过 80 一定换而是能到下一行就换。很多人问要不要拉到 120 或 140我的建议是看团队实际显示器分布。如果大家普遍用宽屏笔记本可以拉到 100 或 120如果项目还要在终端、文档、评审工具里看80 其实更安全。另外行宽越宽单行包含的信息越多code review 时 diff 也越难一眼看全这是很多团队没意识到的代价。tabWidth默认 2控制一个缩进层级占用多少空格。常见选择是 2 或 4团队的代码风格如果已经有明确习惯建议保持因为缩进习惯是整个代码库中最难纠正的部分。useTabs默认 false也就是使用空格缩进。其实我个人并不认为空格比 tab 更“正确”只是大部分现代编辑器对空格的默认支持更稳定。如果团队里有人习惯用 tab可以把它设为 true但一定要保证所有成员使用相同配置否则最常见的现象就是代码里出现混合缩进来回修改特别痛苦。这三个参数有一个共同点需要匹配项目的.editorconfig。如果.editorconfig里写的是indent_size 4而 Prettier 配置是tabWidth: 2那么编辑器保存时 Prettier 和编辑器原生格式化工具会互相打架代码会频繁抖动。我建议先把.editorconfig和 Prettier 配置对齐再去做其他配置。我见过很多团队在这里踩坑原因就是两套配置各管各的。2.2 导致团队分歧最大的三个参数这几个参数值得多说几句因为它们在每个团队几乎都会引发一轮“站队”。semi控制是否在语句末尾加分号。默认 true。JavaScript 语言本身有自动分号插入机制ASI理论上不加也能运行但有几个典型场景会踩坑比如下一行以[或(开头时上一行没加分号就会被解释成函数调用或数组访问。Prettier 会处理一部分这类边界但如果代码里有人手动换行或拼接表达式风险依然存在。我的经验是普通商业项目直接选 true省心真要坚持 false需要在 team review 时特别约定哪些行前面要留保护性分号。singleQuote控制字符串用的是单引号还是双引号。默认 false也就是双引号。这纯粹是习惯问题没有技术优劣。团队如果已经有大量历史代码最好跟历史保持一致避免一次格式化全部翻转。新项目我推荐 singleQuote: true因为单引号在大多数键盘上不需要按 Shift打字略快一点视觉上也更轻。trailingComma控制多行结构的末尾是否加逗号。默认 es5意思是对象、数组这些 ES5 就支持的语法加尾逗号函数参数列表不加。我在实际项目里更喜欢 all也就是函数参数也加尾逗号因为后续增加参数时 git diff 只会显示新增那一行的变化不会把上一行也标成修改。这一点对小团队可能无所谓但在大中型项目里很影响 review 体验。还有个 arrowParens 也要提一句。默认 always就是单参数箭头函数也写(x) 而不是x 。单参数省略括号本来更简洁但在 JSX 中容易产生解析歧义比如const F x div /而且后面要加参数时还要手动补括号。所以我建议保持默认 always。2.3 平时不起眼却容易踩坑的参数这一组参数很小但都容易让人困惑。quoteProps控制对象属性名要不要引号。默认 as-needed也就是能不加就不加。如果把团队代码里大量{key: 1}改成{key: 1}有些调试脚本和代码检索可能受影响但一般情况下 as-needed 没问题。如果希望对象内的属性风格一致可以改成 consistent意思是只要有一个属性必须加引号所有属性都加引号。jsxSingleQuote控制 JSX 属性里用单引号还是双引号默认 false。很多人喜欢 JS 代码里用单引号但 JSX 属性坚持双引号因为这样一眼能区分“这是 JSX 属性”。这个属于团队审美没有对错保持统一就行。bracketSpacing控制对象字面量的花括号内侧是否加空格。默认 true也就是{ foo: bar }。如果喜欢紧凑风格可以设为 false写成{foo: bar}但要注意很多模板引擎、CSS-in-JS 的场景下紧凑风格读起来会累一些。bracketSameLine针对 JSX 的符号。默认 false表示多行 JSX 时另起一行如果设为 true会和最后一个属性保持同一行。这个纯粹看团队排版习惯我自己更喜欢 true因为闭合标签更靠近内容不过 Prettier 默认是 false改不改都行。endOfLine控制换行符类型。默认 lf。这是 Windows 团队最容易踩的坑Windows 默认换行是 CRLF\r\nLinux 和 macOS 是 LF\n。如果大家在一个仓库里协作建议直接固定 lf并且同时配置.gitattributes让 git 不要乱转。embeddedLanguageFormatting控制模板字符串和模板标签中嵌入的代码是否也交给 Prettier 格式化默认 auto。比如有些人会在模板字符串里写 SQL 或 GraphQL希望一起格式化就保持 auto如果因为这些内容被格式化后反而可读性变差就设为 off。htmlWhitespaceSensitivity、vueIndentScriptAndStyle 这两个针对 HTML/Vue 项目。前者默认 css意思是按照 display: css 的语义保留空白对组件库里大量使用 inline-block 或 flex 的场景可能要看下实际效果。后者专门控制 Vue 文件里的script、style内容是否整体再缩进一级默认 false 是让它们跟模板同级我更推荐保持默认。2.4 overrides 和 pragma渐进式接入的法宝Prettier 提供 overrides 机制可以针对不同文件类型覆盖配置。比如 markdown 你想保留原始换行可以这样写{ overrides: [ { files: *.md, options: { proseWrap: preserve } } ] }这个功能在混合项目里非常实用。我做过一个项目里面既有普通 JS 文件又有大量文档如果全局开 proseWrap 会让 markdown 的段落被重新折行文档 diff 变得很乱。用 overrides 单独处理 markdown 后问题就消失了。还有两个针对接入期的参数requirePragma 和 insertPragma。它们配合prettier或format标记使用。requirePragma 为 true 时Prettier 只格式化头部带prettier注释的文件insertPragma 为 true 时格式化文件时会自动插入format标记。我很推荐在存量项目里用这个组合做“白名单式”引入先让一部分迁移完成的文件被格式化而不是一次性把整个仓库翻一遍。2.5 一份可以直接抄的推荐配置如果你不想看前面的长篇分析直接把下面这份配置拿走适用于大多数常规前端项目{ printWidth: 100, tabWidth: 2, useTabs: false, semi: true, singleQuote: true, quoteProps: consistent, jsxSingleQuote: false, trailingComma: all, bracketSpacing: true, bracketSameLine: false, arrowParens: always, endOfLine: lf, embeddedLanguageFormatting: auto }对应的速查表配置项默认值推荐值一句话说明printWidth80100到达阈值后优先换行tabWidth22每个缩进的空格数useTabsfalsefalse是否使用 Tab 缩进semitruetrue是否加分号singleQuotefalsetrue字符串用单引号trailingCommaes5all多行末尾统一加尾逗号arrowParensalwaysalways单参数箭头函数加括号endOfLinelflf统一用 LF 换行这份配置的核心逻辑是尽量接近 Prettier 的默认行为只在几个争议点上做明确选择。记住配得少不等于做得少很多时候“少配置”本身就是团队统一的最好方式。3. 配置文件组织与优先级3.1 四种配置写法怎么选Prettier 支持多种配置文件方式.prettierrc、.prettierrc.json、.prettierrc.yaml、.prettierrc.yml、.prettierrc.js、.prettierrc.cjs、.prettierrc.mjs、prettier.config.js以及package.json里的prettier字段。选择太多时团队最需要的是“统一”。我的建议是能用.prettierrc.json就用 JSON因为它是静态的不会被执行团队成员想改也只改数据。需要写动态逻辑比如根据环境判断字段时才用.prettierrc.js或prettier.config.js但绝大多数项目根本不需要动态逻辑。另外在 Node 项目里如果用 ESM记得用.prettierrc.cjs否则在 CommonJS 环境下 require 一个.js文件可能报错。package.json里的 prettier 字段适合只想少放一个文件的小项目但它的缺点是package.json本身会被频繁修改容易产生没必要的冲突。3.2 查找逻辑与优先级Prettier 配置查找遵循“就近原则”它会从目标文件所在目录开始向上级目录搜索先找到的那个配置文件作为当前文件的配置来源。注意这里不会“合并多个层级的配置”而是找到一个最近的文件后用它的全部字段没写的字段就使用默认值而不是去读取更外层或根目录的另一个配置。这个机制在 monorepo 场景里尤其容易出问题。你可能在仓库根目录放了一个全局配置期望所有包都遵守但某个子包自己放了一个.prettierrc那么这个子包就不会沿用根目录的配置最终两个包风格不一致。解决的办法是要么在每个子包都显式用根配置要么在根目录的 CONTRIBUTING 文档里写明“不要随便在子包添加 prettier 配置”要么直接用 overrides 写在根配置里。另外要注意在 Prettier 3.x 中格式化相关的参数比如 printWidth、semi 这类已经不能通过 CLI 参数临时覆盖了必须写在配置文件里。这个改动我在升级时踩过坑一段时间内团队 CI 脚本里还留着一些--semifalse之类的参数升级后直接报错。所以如果你还维护着旧版本的脚本尽早把它们迁到配置文件中。3.3 CLI 和 ignore日常操作姿势安装 Prettier 后日常用 CLI 的几个命令npx prettier --write ./src/**/*.{js,jsx,ts,tsx,json,css,md} npx prettier --check ./src npx prettier --config .prettierrc --write ./src--write表示直接改写文件--check只检查有没有格式化差异适合放到 CI 里。CI 集成方式一般是在流水线里跑npx prettier --check .如果代码不符合配置就构建失败逼着开发者本地格式化后再提交。这个方式比在 CI 里直接--write更干净因为 CI 不该改动代码。配套的还有.prettierignore文件作用类似.gitignore用来排除不需要格式化的目录。我通常会在里面加这些node_modules/ dist/ build/ coverage/ package-lock.json pnpm-lock.yaml yarn.lock这里要专门提醒package-lock.json、pnpm-lock.yaml这类锁文件如果被格式化会产生大量无意义的 diff而且它们内部的结构往往有其固定格式不要交给 Prettier 处理。还有一些大型 JSON 文件格式化后体积暴增、diff 也很大同样建议 ignore。4. 团队落地完整流程4.1 与 ESLint 正确分工ESLint 和 Prettier 不是同一个层面的东西。ESLint 管的是代码规则比如不允许使用var、不允许隐式类型转换、必须处理 Promise rejection 等Prettier 管的是换行、缩进、引号、空格这些版式问题。如果项目里同时用了两者一定会遇到规则冲突最典型的是 ESLint 的indent、quotes、semi这类规则和 Prettier 的排印策略互相矛盾。标准做法是安装 eslint-config-prettier把 ESLint 里所有“跟格式化相关的规则”全部关掉。这个包的作用其实就是“关闭规则集合”让 Prettier 完全接管排版ESLint 只保留逻辑与潜在错误类规则。如果你用的是 ESLint 9 的 flat config配置里把它展开放进去import eslintConfigPrettier from eslint-config-prettier; export default [ eslintConfigPrettier, // 其他规则... ];还有一个 eslint-plugin-prettier它会把 Prettier 当成一条 ESLint 规则来跑做法是“在 ESLint 内部格式化代码并报告差异”。我个人的建议是尽量不要用这个方案因为性能差等于每次 lint 都先格式化一遍而且它把两个工具耦合成一个流程出问题时更不好排查。常规做法是pre-commit 时用 Prettier 格式化CI 里分别跑 eslint 和 prettier --check两条线互不干扰。这个环节是最值得花时间做对的因为它直接影响每个成员的开发体验。4.2 提交前自动格式化让团队成员手动执行格式化不现实总有遗漏。所以团队落地 Prettier 时提交前的自动格式化要安排上。主流的组合是 Husky 加 lint-staged。现在的 Husky 初始化很简单npx husky-init npx husky add .husky/pre-commit npx lint-staged然后 package.json 里加 lint-staged 配置{ lint-staged: { *.{js,jsx,ts,tsx,vue,json,css,scss,md}: prettier --write } }这里有个细节lint-staged 只处理 git 暂存区的文件所以每次 git add 完后pre-commit 钩子只会格式化本次提交涉及的文件。这样做有两个好处第一是速度快不用全仓库扫描第二是 git blame 不会被一次全量格式化污染历史记录里每一行改动仍然是清晰、有意义的。第一次接入时最好挑一个提交点手动跑一次全量格式化把这个提交单独注明之后再让 lint-staged 接管日常流程历史就干干净净了。如果你还同时用 ESLint可以在 lint-staged 里接着配lint-staged: { *.{js,jsx,ts,tsx}: [prettier --write, eslint --fix] }顺序也重要先 prettier 格式化再 eslint 检查逻辑这样可以避免 eslint 基于没有格式化的代码做判断。整条链路的配置我在几个项目里都验证过稳定且省心。4.3 编辑器保存即格式化CLI 和钩子属于“底线”但多数人希望的是写完代码一保存格式就自动整齐。VS Code 里接 Prettier 是这个时代最顺的路径。首先安装扩展 esbenp.prettier-vscode然后在项目根的.vscode/settings.json里写{ editor.defaultFormatter: esbenp.prettier-vscode, editor.formatOnSave: true, editor.formatOnPaste: false }这里要插一句项目里放.vscode/settings.json是团队统一编辑器行为的关键。如果不放新成员打开项目时用的是自己的编辑器配置可能装了别家的 formatter或者 formatOnSave 根本没开就会出现“代码一保存全变样”“成员间格式不一致”的混乱。我见过最典型的一个场景同事安装了 Beautify、ESLint 扩展又自带了格式化功能三个工具抢一个保存事件最终输出结果跟 Prettier 完全不同。解决办法就是 defaultFormatter 里明确指定 Prettier并且把能关的自动格式化都关掉。另外Prettier 的 VS Code 扩展会默认读取项目里的.editorconfig这一点既是便利也是坑。如果你的.editorconfig里写了indent_style tab而.prettierrc里没写扩展格式化时会按 editorconfig 的规则来但 CLI 格式化时可能就不一样两个入口结果不一致就会让人抓狂。我建议在.prettierrc里把 tabWidth、useTabs 这些关键项显式写出来不要依赖扩展对 editorconfig 的隐式读取。4.4 常用插件与扩展Prettier 本身支持很多语言但有些场景需要插件。这里列几个我实际用到过的。prettier-plugin-tailwindcss专门做 Tailwind CSS 类名排序。它会自动把classmt-4 flex items-center这类长类名按 Tailwind 内置的排序规则整理让相同类别的类名聚在一起。注意它的版本要和 Tailwind 版本匹配否则排序逻辑可能不正确。prettier/plugin-xml格式化 XML 文件用。如果项目里有大量 XML 配置或者 SVG 资源装上后 prettier 就能处理了。prettier-plugin-organize-imports 或 trivago/prettier-plugin-sort-imports做 import 排序。这两个都是社区方案和 Prettier 的配合方式是作为插件挂在配置文件里{ plugins: [trivago/prettier-plugin-sort-imports], importOrder: [^react, ^[a-z], ^/, ^\\.\\./, ^\\./] }这类插件可以统一 import 顺序对强迫症团队很友好但注意插件会增加格式化耗时并且升级 Prettier 主版本时插件可能不兼容需要一起升级。在使用插件时有个小坑如果团队里有人没装配套插件他的格式化输出和装了插件的人不一致。所以团队要约定好要么所有成员都在同一个版本文件里用同一组插件要么把插件通过 npm devDependencies 安装让 npx prettier 运行时统一加载。5. 常见问题与排查技巧实录5.1 配置没生效先查这三件事Prettier 配置“不生效”大概率不是 Prettier 本身的问题而是工具链找错了配置源。我排查的时候按顺序检查三件事。第一项目里是否存在多个同名配置。比如根目录有.prettierrc某个子目录或某层工作区又有一个.prettierrc由于就近原则后者的优先级更高。可以用命令直接查看实际生效的配置npx prettier --find-config-path ./src/index.ts如果返回的路径不是你以为的那个文件说明配置被附近另一个文件劫持了。第二编辑器是否选择了正确的 formatter。格式化结果不对时先在 VS Code 里右键选择“格式化文档方式”看默认是不是 Prettier。有时候装了多个扩展会默认选中别的格式化器这时需要调整.vscode/settings.json。第三版本差异。Prettier 2.x 和 3.x 的配置行为和 CLI 参数有不少变化如果团队里有人本机是 2.x有人是 3.x同一个.prettierrc在两端格式化结果可能不一样。建议在 package.json 里锁定 prettier 版本或者用 npx 统一到同一版本。5.2 格式化结果不统一怎么办经常有两种“不统一”同一个人在不同时间格式化结果不一样不同的人格式化结果不一样。前者通常是因为编辑器缓存或版本升级后者通常是因为配置源不同。多数情况下用上面的“三件事”排查就能定位。还有一个很隐蔽的原因.prettierignore里的文件被跳过格式化而这些文件又和其他人的编辑器自动保存行为相互拉扯。比如有人改了 ignored 文件并保存它的格式和仓库其他文件完全不同下次别人查看时就觉得“怎么又是乱的”。解决方案是把忽略策略公开写进团队文档让每个人都明确“这些文件不享受格式化保护”。还有一种情况是全局配置和项目配置冲突。有些开发者习惯在全局~/.prettierrc里写一套个人偏好配置当项目没有自己的配置时Prettier 会去读全局配置结果每个成员格式化出来都不一样。团队项目能做的就是根目录一定放项目级.prettierrc并且 CI 流程跑--check让不合规的提交直接被拦下。5.3 特定文件格式化不如意时的处理Prettier 不是万能的有些文件格式化结果确实不理想。比如大型模板字符串里的多行 SQL、手写的复杂 JSON 数据、超过特定高度的表格等。这时候可以用prettier-ignore注释局部跳过// prettier-ignore const data { login: admin, password: 123456, token: xxxx, };Prettier 3.x 还支持// prettier-ignore-start和// prettier-ignore-end可以包住一整段代码不用每一行都加注释。这个功能在接入存量项目时特别有用先跳过一部分历史遗留代码等业务稳定后再逐步解除跳过。如果某个文件类型整体都不想被格式化直接在.prettierignore里加一行路径。但要注意格式化的目标不是“所有文件都漂亮”而是“所有被格式化过的文件都符合同一套规则”。所以该忽略的忽略该保护的用 ignore 注释不要指望 Prettier 解决所有排版问题。最后分享一个我自己的体会。Prettier 配置真的是一个“越少越对”的东西。早期我总想通过配置让格式化结果“完美”后来发现团队协作里最完美的状态反而是大家都觉得“就这样吧格式这种破事别讨论了”。把精力留给那些真正需要人的判断力的问题上去这才是 Prettier 存在的意义。