5月27日 21:53
Prettier 是如何工作的?
Prettier 是什么?
Prettier 是一个"有主见"(opinionated)的代码格式化工具,它通过解析代码生成 AST,再用统一的规则重新输出,从而消除团队中的代码风格争议。
工作原理
Prettier 的格式化流程分三步:
1. 解析(Parse):将源代码解析为 AST(抽象语法树)。根据语言不同,选用对应解析器(JavaScript 用 babel,TypeScript 用 typescript 解析器,CSS 用 postcss)。
2. 打印(Print):遍历 AST 生成中间表示 Doc。Doc 的关键设计是"可测量"——Prettier 会先尝试将内容放在一行,超出行宽(默认 80 字符)则自动换行缩进。这比直接输出字符串灵活得多。
js// Prettier 内部 Doc 示意(简化) const doc = group([ "function", " ", "hello", "(", line, "world", ")", " ", "{", indent([line, "console.log(arg);"]), line, "}" ]); // 一行放得下 → 单行输出;放不下 → 自动折行
3. 输出:将 Doc 转换为最终字符串写回文件。相同输入永远产生相同输出(确定性)。
注释处理
注释不属于 AST 节点,是格式化器的经典难题。Prettier 通过独立算法将注释附着到 AST 节点上,再在打印阶段输出到正确位置。
核心设计取舍
- 有限的配置项:有意不支持大量选项(如"函数括号前是否加空格"已被移除),避免团队为风格配置争论
- 多语言支持:JavaScript、TypeScript、CSS、HTML、JSON、Markdown 等均可用同一工具格式化
- 插件机制:通过
parsers和printers扩展新语言或自定义格式化规则
Prettier vs ESLint
| 维度 | Prettier | ESLint |
|---|---|---|
| 职责 | 代码格式(缩进、换行、空格) | 代码质量(未使用变量、潜在 bug) |
| 可配置性 | 少量选项,有态度 | 规则丰富,高度可配 |
| 输出 | 直接修改代码 | 报错或自动修复 |
两者组合使用时,需安装 eslint-config-prettier 关闭 ESLint 中与 Prettier 冲突的格式规则。
Git 提交前自动格式化
结合 husky + lint-staged 可在 commit 前自动格式化:
json// package.json { "lint-staged": { "*.{js,ts,css,md}": "prettier --write" } }
bashnpx husky init echo "npx lint-staged" > .husky/pre-commit
追问
- Prettier 如何处理超长单行代码的折行?Doc 的
group+line机制是如何工作的? - 为什么 Prettier 要引入 Doc 中间表示而不是直接从 AST 输出字符串?
- Prettier 的确定性输出有什么前提条件?什么情况下可能出现不一致?