Prettier:确定性格式、幂等验证与团队基线
Prettier 负责打印,不负责判断代码正确
Prettier 解析支持的语言,再以自己的 printer 生成确定性文本。它能消除缩进、换行、引号和尾逗号争论,却不证明变量已定义、CSS 属性有效或业务逻辑正确。JavaScript 语义进入 ESLint,样式规则进入 Stylelint;格式类规则只能有一个 owner。
本文实验锁定 Prettier 3.9.6。官方明确建议精确锁版本,因为小版本也可能改变输出;升级时以官方 Release和安装指南为准。版本号是实验基线,不是永久最新声明。
精确安装并验证本地解析
npm install --save-dev --save-exact prettier@3.9.6
npm ci
npm exec -- prettier --version
npm ls prettier不要把未安装时的 npx prettier 当团队入口,它可能临时下载不同版本。编辑器也应优先加载项目依赖;在不可信工作区中,编辑器可能退回内置版本,因此 IDE 绿灯不能替代 CLI。
一个克制的 .prettierrc.json:
{
"semi": true,
"singleQuote": false,
"trailingComma": "all"
}Prettier 可以读取部分 .editorconfig,但项目 Prettier 配置优先。相同选项不要同时散落在个人 IDE、CLI 参数和多个嵌套配置中。CLI 决定检查还是写入,仓库配置决定输出。
配置查找必须能解释
Prettier 从目标文件目录向上寻找配置。Monorepo 中不同 package 可能命中不同文件,工作目录也会影响 ignore。用以下命令固定证据:
npm exec -- prettier --find-config-path packages/app/src/main.ts
npm exec -- prettier --file-info packages/app/src/main.ts
npm exec -- prettier packages/app/src/main.ts --check--find-config-path 显示配置来源,--file-info 说明推断 parser 与 ignore 状态。文件未被格式化时先看这两个入口,不能先在编辑器里强制指定 parser。
.prettierignore 划出制品和第三方边界:
dist/
coverage/
generated/
vendor/
*.min.jsPrettier 也会参考同目录 .gitignore。ignore 变化必须在代码评审中展示匹配范围;排除整个源码目录会制造没有差异的假绿。
check 与 write 是两种权限
{
"scripts": {
"format:check": "prettier . --check",
"format:write": "prettier . --write"
}
}--check 不改文件,以非零退出码告诉 CI 存在格式差异。--write 直接覆盖目标文件,只能在开发者明确调用、专门修复任务或独立机器人提交中运行。未经审查的 CI 不应在构建过程中修改源码后继续测试,否则测试对象已经不是提交内容。
先在临时文件制造差异:
const value={name:'demo',items:[1,2,3]}
console.log(value)npm exec -- prettier .quality-smoke/prettier-bad.js --check 应非零。执行一次 --write 后转为通过;再执行第二次 --write,文件哈希应保持不变。这是幂等验证:同一版本、parser、配置与插件对自己的输出再次打印,不应继续产生 diff。
npm exec -- prettier .quality-smoke/prettier-bad.js --write
sha256sum .quality-smoke/prettier-bad.js
npm exec -- prettier .quality-smoke/prettier-bad.js --write
sha256sum .quality-smoke/prettier-bad.js若第二次仍变化,检查插件加载顺序、嵌套配置、不同 CLI 版本或另一个保存修复器。不要用重复执行多次来“最终稳定”。
parser 与插件决定数据解释
Prettier 根据路径和 parser 解析源码。插件可以增加语言或替换 parser/printer,并以当前进程权限执行。插件精确锁定、进入 lockfile 和供应链审查;CI 与编辑器加载同一工作区插件。未知来源插件不能只因为“格式化而已”获得仓库与凭证访问权。
插件版本变化可能未进入缓存键。升级 Prettier 或插件后清理工具与构建缓存,用代表性语言样本运行全量格式差异。包含模板、Markdown、YAML、GraphQL、Vue/Svelte 等多语言仓库,应为每类 parser 保留小型回归样本。
与 Linter 的边界
ESLint 和 Stylelint 中与 Prettier 冲突的纯格式规则应关闭,而不是依赖保存顺序反复改写。eslint-config-prettier 只关闭冲突 ESLint 规则;它不会运行 Prettier。Stylelint 官方也建议将 pretty printer 与 Linter 分工,CSS 正确性和约束仍由 Stylelint 负责。
编辑器保存链只允许一个默认 formatter。ESLint fix 和 Stylelint fix 负责其可安全修复的规则,但不能重新拥有缩进、引号等 Prettier 输出。关闭 IDE 后,npm ci && npm run format:check 应得到同样裁决。
大仓库与分阶段迁移
首次引入可能产生大面积 diff。先冻结工具版本与配置,在独立提交完成纯格式化,再让后续业务分支 rebase;不要把依赖升级、规则变化和业务修改混进同一 diff。无法一次格式化全仓时,可按 package 或目录分批,但 CI 必须明确哪些范围已经纳入,剩余范围有 owner 和退出节点。
只检查改动文件能缩短本机反馈,却不能永久替代主分支全量检查。重命名、配置变化或 parser 升级会影响未改文件,定期或主分支仍运行完整范围。
故障证据
本机与 CI 差异先比较 Node.js、Prettier/插件版本、lockfile、工作目录、配置路径、parser 和 ignore。文件未命中使用 --file-info;配置异常使用 --find-config-path;保存后反复变化则分别关闭 IDE formatter、ESLint fix 与 Stylelint fix,再单独执行各脚本。
报告中的文件路径和格式 diff 可能暴露内部结构,制品按最小权限保留。自动格式化机器人只需要读取仓库和提交分支的有限权限,不持有发布或生产凭证。
升级与回滚
升级前保存旧版本、配置路径、各语言样本哈希、全量差异和耗时。新版本在同一提交运行 --check 与幂等实验,格式变化单独评审;parser 或插件升级与 Prettier 本体分开,便于定位。
回滚恢复 package.json、lockfile、Prettier 配置、ignore、插件和编辑器工作区设置,清理缓存后 npm ci。若升级已经产生纯格式提交,代码 diff 作为独立提交撤销或保留,不能只降版本后留下两套混合输出。门禁最终要证明:配置可定位、目标文件未被误忽略、坏格式会失败、write 后 check 通过、第二次 write 幂等、CI 不改写提交内容。
