Prettier 深度解析(一):设计哲学、配置文件与常见配置项
说实话,我刚开始用 Prettier 的时候,心里是有点抵触的。
你想啊,一个工具连你代码怎么换行都要管,是不是管得太宽了?但后来我在一个 10 人团队里做代码评审,发现每个人写的代码风格都不一样——有人喜欢单引号,有人坚持双引号;有人行尾加分号,有人觉得那是多余。每次合并代码,光改这些格式问题就能吵半天。
直到我把 Prettier 引入项目,世界才清净了。今天我们就来聊聊这个「代码格式界的独裁者」——Prettier。
一、Prettier 的设计哲学:少即是多
Prettier 的核心思想其实就一句话:它不关心你的代码写得对不对,只关心你的代码长得好不好看。
说白了,它是一个「固执己见」的格式化工具。你给它一段乱七八糟的代码,它吐出来的一定是它认为最漂亮的版本。而且它几乎不给你讨价还价的余地——配置项少得可怜,跟 ESLint 那种动辄上百条规则比起来,Prettier 简直像个极简主义者。
Prettier 的三大设计原则:
- 可读性优先:所有格式化规则都围绕「让代码更容易阅读」这个目标
- 输出确定性:同样的输入,永远得到同样的输出,不会因为心情好坏改变格式
- 配置最小化:能不改就不改,默认配置已经足够好
我记得有一次,团队里有个新人问我:「为什么 Prettier 要把我的三元运算符拆成三行?我觉得一行更简洁啊。」
我当时的回答是:「你觉得一行简洁,但 Prettier 觉得一行太长,影响阅读。它不会跟你商量,因为它知道什么对团队最好。」
嗯,这就是 Prettier 的哲学——放弃个人审美,拥抱统一标准。
二、配置文件(.prettierrc)详解
Prettier 支持多种配置文件格式,我个人最常用的是 .prettierrc 的 JSON 格式,简单直观。
2.1 支持的配置文件格式
| 格式 | 文件名 | 示例 |
|---|---|---|
| JSON | .prettierrc 或 .prettierrc.json |
{ "semi": false } |
| YAML | .prettierrc.yaml 或 .prettierrc.yml |
semi: false |
| TOML | .prettierrc.toml |
semi = false |
| JS | prettier.config.js 或 .prettierrc.js |
module.exports = { semi: false } |
| package.json | 在 package.json 中添加 prettier 字段 |
"prettier": { "semi": false } |
我建议团队项目统一使用 .prettierrc 文件,放在项目根目录。这样每个人进来一看就知道格式规则在哪,不用去翻 package.json。
2.2 配置文件的优先级
Prettier 查找配置文件的顺序是这样的:
- 先找当前文件所在目录的配置文件
- 如果没找到,往父目录找,直到项目根目录
- 如果还没找到,用用户主目录下的全局配置
- 最后才是默认配置
小技巧: 如果你想让某个子目录使用不同的格式规则,可以在该目录下放一个独立的 .prettierrc 文件。我曾经在一个 monorepo 项目里,给前端和后端分别配置了不同的 printWidth,因为后端代码逻辑复杂,需要更宽的行宽来展示完整逻辑。
三、常见配置项详解
Prettier 的配置项虽然少,但每个都很关键。下面我挑几个最常用的,结合我的实际经验来讲。
3.1 printWidth:一行多长才算长?
默认值是 80,单位是字符。这个值决定了 Prettier 什么时候该换行。
// 当 printWidth = 80 时,这行代码会被换行
const veryLongVariableName = someFunction(argument1, argument2, argument3, argument4, argument5);
// 格式化后:
const veryLongVariableName = someFunction(
argument1,
argument2,
argument3,
argument4,
argument5
);
我个人习惯把 printWidth 设为 100。为什么?因为现在的显示器都宽了,80 个字符太浪费空间。但我也见过一些老派开发者坚持用 80,说是在终端里看代码更舒服。嗯,这个看团队习惯吧。
注意: printWidth 不是硬限制,而是一个「建议值」。Prettier 会尽量让代码不超过这个宽度,但如果实在没办法(比如一个很长的 URL 字符串),它也不会强行截断。
3.2 tabWidth:缩进用几个空格?
默认值是 2。这个配置决定了每个缩进级别用几个空格。
// tabWidth = 2
function foo() {
if (true) {
console.log('hello');
}
}
// tabWidth = 4
function foo() {
if (true) {
console.log('hello');
}
}
我曾经在一个老项目里看到 tabWidth 设为 8,那代码缩进简直像楼梯一样,嵌套三层就看不到右边了。后来我果断改成了 2,世界瞬间清爽了。
3.3 semi:分号到底要不要?
默认值是 true,也就是要加分号。但很多 JavaScript 开发者喜欢不加分号,觉得代码更简洁。
// semi: true
const a = 1;
const b = 2;
// semi: false
const a = 1
const b = 2
这里我要说一个坑:如果你选择不加分号,一定要确保代码不会因为 ASI(自动分号插入)机制出问题。
我曾经遇到过这样一个 bug:
// 没有分号的情况下
const value = someFunction()
[1, 2, 3].forEach(item => console.log(item))
// 实际上被解析成了:
const value = someFunction()[1, 2, 3].forEach(item => console.log(item))
// 直接报错!
所以我的建议是:新项目可以不加分号,但老项目保持原样。不要为了追求「简洁」而引入潜在的 bug。
3.4 singleQuote:单引号还是双引号?
默认值是 false,也就是用双引号。我个人更喜欢单引号,因为少按一个 Shift 键。
// singleQuote: true
const name = 'hello world'
// singleQuote: false
const name = "hello world"
避坑指南: 如果你在写 JSX,Prettier 会自动把 JSX 属性里的引号强制改成双引号,不管你怎么配置 singleQuote。这是因为 JSX 规范要求属性值用双引号。嗯,这个没办法,Prettier 就是这么固执。
3.5 trailingComma:尾逗号要不要?
默认值是 'es5',也就是在 ES5 允许的地方加尾逗号(比如对象和数组)。
// trailingComma: 'es5'
const obj = {
name: 'Alice',
age: 30, // 这里加了逗号
}
// trailingComma: 'none'
const obj = {
name: 'Alice',
age: 30 // 没有逗号
}
我个人强烈建议开启尾逗号。为什么?因为当你新增一行时,不需要修改上一行。这样 git diff 会更干净,只显示新增的行,而不是「新增一行 + 修改上一行加逗号」。
3.6 bracketSpacing:对象括号内要不要空格?
默认值是 true,也就是在花括号内加空格。
// bracketSpacing: true
const obj = { foo: 'bar' }
// bracketSpacing: false
const obj = {foo: 'bar'}
这个纯粹是审美问题。我个人觉得加空格更易读,但如果你喜欢紧凑风格,也可以关掉。
四、知识体系结构图
下面我用一张 SVG 图来总结 Prettier 的核心知识体系:
五、一个完整的配置示例
最后,给你看看我常用的配置,你可以直接拿去用:
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf"
}
这个配置我用了好几年,在多个项目里验证过,基本没出过问题。当然,你也可以根据自己的喜好调整。记住一点:配置定了就别轻易改,否则团队又要重新适应。
好了,关于 Prettier 的设计哲学和配置项,今天就聊到这里。下一节我们会深入 Prettier 的解析器和插件机制,看看它到底是怎么把代码「变好看」的。