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 等均可用同一工具格式化
  • 插件机制:通过 parsersprinters 扩展新语言或自定义格式化规则

Prettier vs ESLint

维度PrettierESLint
职责代码格式(缩进、换行、空格)代码质量(未使用变量、潜在 bug)
可配置性少量选项,有态度规则丰富,高度可配
输出直接修改代码报错或自动修复

两者组合使用时,需安装 eslint-config-prettier 关闭 ESLint 中与 Prettier 冲突的格式规则。

Git 提交前自动格式化

结合 husky + lint-staged 可在 commit 前自动格式化:

json
// package.json { "lint-staged": { "*.{js,ts,css,md}": "prettier --write" } }
bash
npx husky init echo "npx lint-staged" > .husky/pre-commit

追问

  • Prettier 如何处理超长单行代码的折行?Doc 的 group + line 机制是如何工作的?
  • 为什么 Prettier 要引入 Doc 中间表示而不是直接从 AST 输出字符串?
  • Prettier 的确定性输出有什么前提条件?什么情况下可能出现不一致?
标签:Prettier