配置格式

Prettier 与 ESLint 协作:格式化与代码规范落地不打架

Prettier 管格式化、ESLint 管代码质量,但两者规则重叠时容易互斥,pre-commit 跑起来鸡飞狗跳。本文讲清怎么划分职责、如何关闭冲突规则、以及统一配置并在 CI 强制生效。

作者:巧匠团队·7 分钟阅读·更新于 2026-09-06

先想清楚:Prettier 管排版,ESLint 管对错

二者职责完全不同:Prettier 只关心代码长什么样——引号、分号、缩进、换行——它是"格式美容师";ESLint 关心代码是否犯了规则错误——未使用变量、潜在 bug、强制风格——它是"语言裁判"。

很多团队把它们混为一谈,结果同一个缩进规则在两边都配置,互相打架。正确的心智模型:格式化问题全部交给 Prettier,ESLint 中任何与格式相关的规则(indent、quotes、semi)都要关掉,交给 Prettier 去处理。这样两端各管一摊,规则不会冲突。

{"semi": true, "singleQuote": false, "trailingComma": "all"}
# ----------------------------------------------
// .prettierrc 常见配置
module.exports = {
  semi: true,
  singleQuote: true,
  printWidth: 100
};

用 eslint-config-prettier 关掉冲突规则

ESLint 内置和 Prettier 冲突的格式规则很多(indent、quotes、no-mixed-spaces-and-tabs 等)。最省事的解法是引入 eslint-config-prettier,它会把所有与格式化冲突的规则一键关闭。

具体做法是在 ESLint 配置的 extends 里,把 prettier 放在最后一个覆盖项。注意追加顺序:extends 数组后写的优先级更高,所以 prettier 必须排在最末,这样它在报冲突信息时的"关掉"能真正压过前面的规则集。

配置完跑一遍 npx eslint . 确认没有残留的格式类报错,如果仍报"格式错误",多半是内联禁用注释或某些规则没被关全,再去 extends 里检查覆盖顺序。

// .eslintrc.js
module.exports = {
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"   // 必须放最后,关闭与格式冲突的规则
  ]
};

一次统一:让 Prettier 参与编辑器和 CI,别只在本地跑

只装依赖不够,格式化要在编辑器里实时生效。VSCode 装 Prettier 扩展后,把 default formatter 设为 prettier,并开启 format on save 与保存时 eslint --fix。这样提交的每条代码都已经被自动整理过。

但要防止"我本地格式化过、别人没格式化就提交"的漂移,唯一的硬约束在 CI:跑 prettier --check . 和 eslint .,任何一边失败就阻断合并。本地用 pre-commit hook(lint-staged)对暂存文件做增量格式化 + CLI 直跑做兜底,双保险。

# VSCode settings.json
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }
# -------------------------------------------------
# package.json scripts
"lint": "eslint .",
"format:check": "prettier --check ."

lint-staged:pre-commit 只处理暂存区,别全量跑

在 husky 的 pre-commit 里直接跑 eslint . 在大仓库会很慢,因为每次提交都在全量扫描。用 lint-staged 可以做到只对本次 staged 的文件做格式化与 lint,配合 staged 的 .ts/.tsx/.vue 文件列表。

典型的 husky + lint-staged 组合:提交时对暂存文件先 prettier --write 再 eslint --fix,通过后才允许提交。注意把需要处理的文件扩展名列全(vue、ts、tsx、json、md 等),漏了某个类型就等于是没检查。

这样每个提交都是当时就格式化好的,CI 里的 check 用 --check 验证而非再写一遍,避免本地提交与 CI 结果不一致。

// .lintstagedrc
{
  "*.{js,ts,tsx,vue}": ["prettier --write", "eslint --fix"],
  "*.{json,md,yaml}": ["prettier --write"]
}
# -------------------------------------------------
// package.json
"lint-staged": {
  "*.{js,ts,tsx,vue}": ["prettier --write", "eslint --fix"]
}

验证:给出基准并对比格式化前后的差异

配置收尾不能只看"能跑"。先建一个示例文件故意写得混乱(引号混用、缩进不定、行过长),跑一遍 prettier --write 观察它是否被整理成预期的统一风格;再跑 eslint . 确认格式类规则不报冲突、只剩真正的质量问题。

然后跑 prettier --check . 应返回 0、eslint . 应无 error,接着提交一次确认 pre-commit 的 lint-staged 真的拦截过(故意塞一个格式脏文件看它被拒绝)。最后在 CI 里放入同样的 check,并在团队 README 写明"任何风格问题先跑格式化,不要手改"。

把 .prettierrc 与 ESLint 配置纳入 code review 的必检项,避免后续有人为了局部需求往里塞冲突规则。

npx prettier --write ./demo.ts   # 先统一坏文件
npx prettier --check .            # 期望退出码 0
npx eslint .                      # 期望 0 error
echo $LASTEXITCODE                # 0 表示通过

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。