1. 为什么团队里最沉默的痛点,往往出在"代码长得不一样"上
代码格式化这件事,说大不大,说小不小。我见过太多团队,业务逻辑没吵起来,先在"花括号到底换不换行""缩进用两个空格还是四个空格""单引号还是双引号"这些事上耗掉大量精力。每次 Code Review,评论区一半的讨论都跟逻辑无关,全是在说排版。这个问题不解决,代码审查的质量和效率都会被拖垮。
Prettier 就是冲着这个痛点来的。它是一个固执己见的代码格式化工具,核心思路非常简单:你负责写对,它负责排整齐。不管是 JavaScript、TypeScript、CSS、HTML、JSON 还是 Markdown,只要你把代码交给它,它就按照一套统一的规则输出格式,让你的代码外观整齐划一。它的设计哲学里有一条很反直觉但很实用的原则:唯一的风格选项才是最好的选项。你不需要去配置"大括号换行方式我有12种偏好",Prettier 只给你几个关键的开关,剩下的全按照社区公认的最佳实践来。
这篇文章适合谁看?你是一个人的全栈开发者,想让自己的代码看着舒服点;或者你是前端团队的技术负责人,正在推动代码风格统一;又或者你只是被 ESLint 的格式规则折磨过、想找个解决方案的新手——这篇文章都能给你一个可以直接上手的完整方案。我还会分享一些实际踩过坑之后总结出来的参数配置经验,比如为什么 Print Width 不宜拉太长、为什么 Trailing Comma 推荐用 es5 而不是 all、怎么让 Prettier 和 ESLint 不打架,这些细节在官方文档里不会讲得那么细,但对真实项目来说非常关键。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心思路拆解:Prettier 的"固执"是对的
2.1 格式化工具那么多,为什么偏选 Prettier
在我接触 Prettier 之前,市面上的方案大致分两种。一种是编辑器自带的格式化功能,比如 VS Code 的 Format Document,它提供的选项多到让人眼花缭乱,但问题恰恰出在"选项多"上——每个开发者都可以按照自己的偏好配置,最后每个人提交到仓库的代码风格还是五花八门。另一种是 ESLint 这类 Linter 自带的格式规则,理论上它能检查代码风格,但它的设计初衷是"发现问题"而不是"重建排版",你写错了格式它会报错,却不会主动帮你把整个文件整理得服服帖帖,而且配置格式规则的代价极高,性能也比专门的格式化工具差很多。
Prettier 的定位完全不一样。它是一个单一职责的工具,只做代码解析和重新打印。它内部用的是自己开发的解析器,先把代码读成一棵抽象语法树(AST),然后完全忽略你原本是怎么写的,只根据 AST 结构重新打印出一份格式统一的代码。这个过程意味着什么?意味着无论你原来是那种风格,经过 Prettier 处理之后,输出结果是一模一样的。这就是"固执己见"的真正含义,也正是它能作为团队统一标准的最核心原因。
2.2 AST 重打印:为什么 Prettier 能做到"格式化完还能跑"
很多刚接触 Prettier 的人会担心一个问题:它把代码重新排版之后,会不会改变代码的逻辑?甚至担心它会不会因为解析失败直接报错。其实这个担心多余了,但背后的原理值得说清楚。
Prettier 处理代码的过程大致分三步。第一步是解析,它读取源代码文件,根据文件后缀选择合适的解析器,把文本转换成 AST。AST 是语法层面的结构化表示,它只关注代码的语法含义,完全不关心空格、换行、缩进这些外观层面的东西。比如 const a=1 和 const a = 1,这两行代码在 AST 层面是完全一样的。第二步是打印,Prettier 会遍历 AST,按照自己内置的打印规则,把每个节点渲染成一行行的文本。这一步就是它决定"花括号怎么放""缩进几个空格"的地方。第三步是输出,把打印好的文本写回文件。
因为整个过程完全基于 AST,而不是基于正则匹配或文本替换,所以格式化之后代码的逻辑不会变。这也是我推荐在任何规模的项目里都放心使用 Prettier 的原因。不过有一点要提醒:Prettier 对语法错误是零容忍的,代码有语法错误时它会报错并拒绝格式化。这反而是个优点,等于帮你做了一次被动语法检查。
2.3 为什么选择"少配置":Option 越少,冲突越少
我第一次配置 Prettier 的时候,总觉得默认配置不够,想调这个调那个。后来用了一段时间才发现,Prettier 团队刻意控制配置项的规模,是深思熟虑的结果。对比一下其他格式化工具动辄几十个选项,Prettier 的核心配置项大概只有十几个,很多还是布尔开关。
这个设计决策背后有一个很现实的逻辑:格式化工具的配置项一旦多了,团队里就容易出现"你选 A,我选 B"的分歧,各说各有理,最后还是在争论中内耗。Prettier 直接把大部分风格决策帮你做了,你只剩下一小部分真正需要团队达成一致的选项可以调。这样反而促成了统一,因为大家没有那么多理由去争。
我在实际项目里的体会是,配置项越少,落地成本越低。你不需要为新加入团队的成员准备一份厚达几十页的代码风格文档,只要跟他说"代码提交前跑一下 Prettier 就行",整个团队的代码风格就自然一致了。这在团队规模扩大时节省的成本非常可观。
3. 从零配置到实际落地:Prettier 的完整实操指南
3.1 环境准备与快速安装
先把安装这一步说清楚。Prettier 可以在全局安装,也可以在项目目录下安装。我强烈建议安装在项目本地,因为不同项目的 Prettier 版本可能不同,全局版本会导致项目之间互相干扰。而且本地安装之后,配合 package.json 里的脚本,新成员 clone 项目后执行 npm install 就能获得完全一致的工具版本,这是工程化落地的基本要求。
本地安装命令:
bash复制npm install --save-dev --save-exact prettier
这里有个细节值得注意,我用了 --save-exact。为什么要锁版本?因为 Prettier 的不同版本之间偶尔会有格式化规则的变化,同一个文件在 v2 和 v3 下可能格式化成不同的样子。如果不锁版本,团队里有人安装了新版本之后跑一遍格式化,可能把全仓库几十个文件都改了,Code Review 根本没法看。这个问题我在真实项目中踩过,所以现在逢人就说:Prettier 一定要锁版本。
安装完成后,在 package.json 里加一条脚本:
json复制{
"scripts": {
"format": "prettier --write \"src/**/*.{js,ts,json,md}\""
}
}
这样你只需要在终端跑 npm run format,Prettier 就会自动格式化 src 目录下所有匹配的文件。--write 参数的意思是直接覆盖写入文件,如果不加这个参数,Prettier 只会把格式化后的结果打印到终端,不会修改原文件。
3.2 核心配置项解析:这些参数到底在管什么
Prettier 的配置可以通过三种方式提供:.prettierrc 文件、prettier.config.js 文件,或者 package.json 里的 prettier 字段。我推荐用 .prettierrc.json,理由很简单:它作为一个独立的 JSON 文件,不污染 package.json,而且让新人一眼就能看到项目的格式化配置在哪里。
我整理了一份我常用的基础配置,可以作为团队的起点:
json复制{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"useTabs": false,
"trailingComma": "es5",
"printWidth": 100,
"endOfLine": "lf"
}
逐个说说这些参数以及我为什么这么选。
semi 控制行尾是否加分号。我选 true,因为项目里同时有 JavaScript 和 TypeScript,自动插入分号机制在现代语法下通常没问题,但在某些场景下仍然可能埋坑。团队协作时,显式分号能减少认知负担,也减少"为什么这行没报错那行报错了"这类无谓的排查。
singleQuote 决定字符串用单引号还是双引号。我选 true,原因很纯粹:大部分前端项目更习惯单引号,且单引号在按 Shift 时少了一个键,输入效率略高。不过要注意,在 JSX 组件里 Prettier 默认会强制使用双引号,这是 JSX 规范的一部分,不需要额外配置。
tabWidth 设成 2,useTabs 设为 false,意思是缩进用两个空格而不是 Tab。这个组合是 JavaScript/TypeScript 生态里的绝对主流。
trailingComma 的值有三个选项:none、es5、all。none 表示不加尾逗号,es5 表示在 ES5 合法的位置加尾逗号,比如对象和数组,all 表示在函数参数和调用处也加。我推荐 es5 而不是 all,因为 all 在函数参数末尾加分号在某些旧版 Node 环境或某些编译工具链下可能会出问题。追求极致统一的话可以选 all,但要确认你的工具链支持。
printWidth 设定每行代码的最大宽度,超过这个宽度 Prettier 会尝试换行。我设成 100,这是个折中方案。设太短比如 80,很多长语句会被拆成多行,阅读体验反而碎片化;设太长比如 120,在分屏写代码或者做 Code Review 时,横向滚动让人抓狂。
endOfLine 可以设为 lf、crlf 或 auto。我选 lf,因为跨平台团队最大的隐形杀手就是行尾符不一致。Windows 默认用 CRLF,Linux/macOS 用 LF,如果文件混着两种行尾符,Git 会在 diff 里报一堆莫名其妙的改动。Prettier 统一转成 LF 之后,这个问题从根上就解决了。
3.3 忽略文件:不是所有代码都需要格式化
有些场景下你并不想让 Prettier 碰某些文件。比如第三方库的压缩版本、自动生成的文件、某些特殊格式的配置文件。Prettier 提供了 .prettierignore 文件来解决这个问题,语法和 .gitignore 一致。
我通常在 .prettierignore 里加上这些内容:
code复制dist
build
node_modules
package-lock.json
pnpm-lock.yaml
*.min.js
coverage
这里要特别说下 package-lock.json。它里面的依赖版本树是程序生成的,格式非常严格,Prettier 格式化它们不仅没有意义,还可能把文件改得和实际安装的依赖对不上。虽然有锁文件内容本身不会因为格式改变而失效,但完全没必要去冒这个险。
3.4 与编辑器集成:保存即格式化
命令行工具只是 Prettier 的一种使用方式,对日常开发来说,编辑器集成才是影响开发体验的关键。我以 VS Code 为例,说一下配置步骤。
首先在扩展市场安装 Prettier 扩展,然后打开用户设置 JSON,添加以下配置:
json复制{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
这段配置的作用是,当你按下 Ctrl+S 保存文件时,编辑器自动调用 Prettier 格式化这个文件。这是一个"让人上瘾"的体验:你只管写,保存之后代码自动变得整齐,好习惯不需要靠意志力维持,工具帮你完成了。
有一点要提醒,有些人习惯在全局设置里把 editor.formatOnSave 设成 true,但这可能导致你打开别人项目时,保存一个文件就把整个文件的格式改了,产生大量与你本次改动无关的 diff。我的建议是,formatOnSave 最好通过项目的 .vscode/settings.json 配置,跟着仓库走,而不是写进个人全局配置。这样换项目时行为可预期。
3.5 与 Git Hooks 结合:提交前自动格式化
编辑器保存格式化覆盖了日常开发的大部分场景,但总有漏网之鱼,比如有人用命令行改文件、或者忘了安装编辑器扩展。要确保进入 Git 仓库的代码百分之百经过格式化,最佳实践是在提交代码之前挂一个 Git Hook 自动执行 Prettier。
最常用的工具有两个:husky 配合 lint-staged。lint-staged 的作用是只对暂存区的文件执行命令,这样每次提交时格式化的文件数量极少,速度极快,也不会把无关文件改掉。
安装步骤:
bash复制npm install --save-dev husky lint-staged
npx husky-init
然后在 package.json 里配置 lint-staged:
json复制{
"lint-staged": {
"*.{js,ts,jsx,tsx,json,md,css,html}": ["prettier --write"]
}
}
再在 .husky/pre-commit 文件里加上:
bash复制npx lint-staged
这样每次执行 git commit 时,暂存区里的代码文件都会被 Prettier 先格式化一遍,如果有文件格式变了,它们会被重新暂存并包含进本次提交里。这个流程在团队协作时能保证所有提交都格式统一,省去了专门的"代码风格 Review"环节。
4. 实操中的高频问题与排查方法
4.1 Prettier 和 ESLint 冲突怎么办
这个问题我几乎每周都能看到有人问。ESLint 的规则里有一些是格式化相关的,比如缩进规则 indent、引号规则 quotes、逗号规则 comma-dangle,这些规则和 Prettier 的功能有重叠。如果你同时启用两者,就会出现一个尴尬的局面:Prettier 刚把代码格式化成自己认为对的样子,ESLint 跑过来报"缩进不正确",两边吵起来了。
解决方案是让两者职责分明:ESLint 只负责代码质量检查,格式问题交给 Prettier。具体做法是,在 ESLint 配置中关闭所有与格式化相关的规则。如果你用的是 ESLint 8 之前的版本,需要手动关闭这些规则;如果你用的是 ESLint 9 或更高版本,可以用 eslint-config-prettier 这个配置包来自动关闭所有与 Prettier 冲突的规则。
安装方式:
bash复制npm install --save-dev eslint-config-prettier
然后在 ESLint 配置文件的 extends 数组里,把 prettier 放在最后:
json复制{
"extends": ["eslint:recommended", "plugin:react/recommended", "prettier"]
}
顺序很重要,prettier 必须放在最后一位,这样它才能覆盖掉前面其他配置里与格式化相关的规则。这是一个很小但非常实用的细节,我见过有人把顺序搞反了,结果冲突依旧在。
4.2 格式化范围太大,整个文件都被改了
最典型的一个场景是:你接手一个老项目,里面有些文件还是老风格,你想改一行代码,结果用 Prettier 一保存,整个文件几百行的格式都变了。这种情况下,Code Review 的 diff 会非常难看,审查的人根本分不清哪些是你的实际改动,哪些只是格式化造成的。
针对这种情况,我有几个应对方案。一是用到 Prettier 的 --range-start 和 --range-end 参数,只格式化指定范围的代码。但这个方式在编辑器里不太常用,因为你需要精确知道行号。二是在编码前先对整个文件执行一次格式化,把格式化的改动作为一次独立的 commit,之后你再做逻辑改动,两者分开。这是一个非常实用的工作流习惯:先格式化提交,再功能提交,diff 干干净净。三是最彻底的方案,对整个项目做一次全量格式化,把这一次格式化作为一次单独的提交,后续所有人的代码都在统一格式的基础上进行。这种"破窗效应"的修复方式,成本是一次性的,收益是长期的。
4.3 格式化结果不符合预期怎么办
Prettier 大部分时候的输出是很合理的,但偶尔你会遇到"这行代码它为什么要这么断"的情况。比如一个函数调用,你希望它的参数保持在一行内,但 Prettier 觉得超出了 printWidth,就强行拆成多行。这种时候,大多数人第一反应是我去调打印宽度,但我建议你慎重。
如果只是想处理个别特殊场景,Prettier 提供了注释指令来跳过格式化:
js复制// prettier-ignore
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
在代码前面加一行 // prettier-ignore,Prettier 就会跳过它,原样保留这段代码的格式。注意,prettier-ignore 必须放在它要保护的代码的正上方,中间不能有空行。
不要滥用这个功能。如果某个文件里到处都是 prettier-ignore,说明你的整体配置或代码逻辑可能有别的问题。我在实际项目中只在两处用了这个指令:一处是某些刻意对齐的复杂嵌套数组,另一处是自动生成的包含特定格式约定文件的代码。其他情况下,都随 Prettier 去格式化,反而省心。
4.4 格式化速度慢?多半是文件过大的问题
Prettier 的速度整体是很快的,但在个别场景下也会慢到让人怀疑人生,最常见的原因就是处理大型 JSON 文件或者包含超长行代码的文件。比如一个压缩过的 JSON 文件,所有内容都在一行里,有几万甚至几十万个字符,Prettier 要解析这行,然后重新打印,性能会大打折扣。
解决办法很简单:这类文件放进 .prettierignore 里,不让它格式化。压缩过的文件本身就不适合人类阅读,格式化它们没有任何意义。还有一个诚实的建议:如果某个手写的源文件大到格式化要几秒钟,那这个文件本身可能设计上需要拆分重构了,它已经超出了合理维护的粒度。
4.5 团队新成员没有安装编辑器扩展
就算项目配置了 Git Hook,新成员在写代码时如果编辑器没装 Prettier 扩展,开发体验也会很割裂。我见过不止一次:新人提交的代码因为没被格式化,导致 Git Hook 生效后,他本地文件被改得跟他写的不一样,他一脸懵。
解决这个问题的好办法是使用 VS Code 的工作区推荐扩展机制。在仓库里创建 .vscode/extensions.json:
json复制{
"recommendations": ["esbenp.prettier-vscode"]
}
新人打开项目时,VS Code 会自动弹窗推荐安装这个扩展,即使他想装错都不太可能了。这个配置文件应该随仓库提交,这样所有开发者的编辑环境就能有基本的共识。
5. 进阶实践:从单人工具到团队规范的进阶之路
5.1 与 Vue/React 项目的配合细节
这几年我用 Prettier 配合 Vue 3 和 React 项目踩了不少坑,这里单独拎出来讲。Vue 单文件组件里面包含 <template>、<script>、<style> 三个区块,Prettier 本身支持 Vue 文件的格式化,但需要依赖 @vue/compiler-sfc,这个依赖会在安装 Vue 3 项目时自动带上,所以基本没问题。
不过有几个格式上的细节值得注意。模板里的一段长表达式是否换行、标签之间的空白怎么处理、<script setup> 中暴露的变量名怎么排序,这些在 Prettier 中仍然遵循它固有的规则,可能跟团队之前的习惯不一致。所以我的建议是:在一个全新的 Vue 3 + Vite 项目中,从第一天就引入 Prettier,让所有代码从一开始就采用统一格式,这比后期再迁移要省无数倍的力气。
React 项目则要注意 JSX 的格式化行为。Prettier 会把过长属性的 JSX 标签自动拆成多行,每个属性单独一行。这个行为在刚开始可能会让人不太适应,但适应之后你会发现这样排版的 JSX 在 Code Review 时属性变更非常容易看出来,因为 Git diff 能精确到每一行的属性变化。
5.2 在新项目里落地 Prettier 的标准流程
如果你想在一个新项目里从零搭建 Prettier,我建议按这个顺序操作:
- 安装依赖并配置
.prettierrc.json,基础参数见上面 3.2 节。 - 创建
.prettierignore,把不需要格式化的目录和文件排除。 - 在
package.json中添加format脚本。 - 安装并配置 ESLint 和
eslint-config-prettier,确保两个工具不冲突。 - 安装配置 husky 和 lint-staged,在 Git 提交时自动格式化。
- 在项目里创建
.vscode/extensions.json,推荐团队成员装扩展。 - 全量执行一次
npm run format,把整个项目的代码格式统一,然后单独提交这一次格式化改动。
之前我帮一个团队做过类似的迁移,整个流程走下来大约半小时就完成了。关键的坑在第 7 步,一定要把格式化提交单独做,不要和业务代码混在一起,这样如果后面有人想知道某个文件是什么时候被格式化的,查 Git 提交历史就能说得清楚。
5.3 CI 环节的强制性检查
Git Hook 只能拦截本地提交,理论上只要你绕过了 hook 或者对 hook 动过手脚,不规范代码还是有可能进到仓库里。真正强力的兜底手段是在 CI(持续集成)里增加一个格式化检查的步骤。
这里有一个思路,将 prettier --check 加入 CI 脚本,它不会改写代码,只检查代码是否符合规范,不符合则退出并报错。如果某个提交没有经过格式化,CI 就会直接失败,迫使提交者回到本地重新格式化再推送。
CI 配置片段(以 GitHub Actions 为例):
yaml复制- name: Check Prettier
run: npx prettier --check "src/**/*.{js,ts,tsx,json,md}"
为什么我不直接推荐在 CI 里执行 --write?因为 CI 环境通常只读,而且自动修改代码会掩盖问题,让人对格式化的过程失去警觉。--check 能精确地告诉开发者"你这次提交里有哪几个文件格式不对",这个反馈对培养规范意识很有用。
5.4 代码格式化的收益衡量
我知道有些同事会问:"花这么多精力在一个代码格式工具上,值吗?"我的回答是,要算清这笔账得看长期成本。代码格式化这件事,如果靠人肉自觉去维持,成本是每人每天写代码时都要分心去关注排版,Code Review 时又额外花时间review格式,这在项目大了之后,累积成本可怕。
Prettier 的价值不在于让代码"更好看",而在于把人的注意力从外观维护中解放出来,让它可以集中在逻辑和架构上。代码审查的效率提升、新人上手速度的提升、跨分支合并时冲突减少,这些都是实实在在的收益。我接触过的团队里,凡是坚持用 Prettier 一年以上的,几乎都回不去"手动排版"的日子了,因为一旦体验过"保存即格式化"的爽感,就很难再接受提交前还要逐个文件调整缩进的生活了。
回头说说我自己的体会。刚开始接触 Prettier 时,我也不太习惯它那种什么都管的行为,总觉得几个参数没调到位,但用久了才发现,真正让你省心的不是某个参数值,而是"不用再想这件事"的感觉。代码风格统一这件事,依靠的是工具而非自觉,这是团队效率提升里最轻松的一步。如果你还没有在项目里引入 Prettier,我建议就从今天开始,先在一个小项目里跑一遍,感受一下保存即格式化的顺畅,再逐步推广到整个团队。
