如何在 CI/CD 中集成 Prettier 做代码格式检查?
为什么要用 Prettier 拦截代码格式问题
代码格式不一致是团队协作中最容易引发无意义争论的问题。Prettier 通过"零配置强制统一"的思路消除了这类争议,但仅靠开发者自觉运行 Prettier 并不可靠——有人会忘记格式化,有人会选择性忽略。把 Prettier 检查嵌入 CI/CD 流水线,是保证代码库格式一致性的最后防线。
推荐的两层防护策略:本地 Git Hook 做即时拦截 + CI 流水线做兜底检查。前者让开发者在提交前就能发现问题,后者防止绕过 Hook 的代码进入主分支。
本地拦截:Git Hooks 配置
Husky + lint-staged 方案
这是目前最主流的方案,lint-staged 的核心优势是只格式化本次提交涉及的文件,不会全量扫描,提交速度有保障。
-
安装依赖
bashnpm install --save-dev husky lint-staged prettier npx husky install npm pkg set scripts.prepare="husky install" -
配置 lint-staged
在
package.json中添加:json{ "lint-staged": { "*.{js,jsx,ts,tsx}": [ "prettier --write" ], "*.{json,css,scss,md}": [ "prettier --write" ] } }分开配置的好处是后续可以为 JS/TS 文件加入 ESLint 检查,而不影响纯样式或文档文件。
-
创建 pre-commit Hook
bashnpx husky add .husky/pre-commit "npx lint-staged"
常见坑:Husky 不生效
- 未执行
husky install:克隆仓库后需要手动运行一次npm prepare - corehooks 被覆盖:某些工具(如 Gerrit)会修改 Git hooks 路径,检查
git config core.hooksPath - lint-staged 卡住:文件路径含空格或中文时需要用引号包裹 glob 模式
CI 流水线集成
GitHub Actions
创建 .github/workflows/prettier.yml:
yamlname: Prettier Check on: push: branches: [main] pull_request: branches: [main] jobs: prettier: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm ci - run: npx prettier --check "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}"
关键细节:
- 用
npm ci而非npm install,前者严格按照 lock 文件安装,CI 环境更稳定 --check模式只检查不修改,符合 CI "只读" 原则- 缩小 glob 范围到
src/目录,避免扫描 node_modules 或构建产物
如果希望 PR 中直接看到哪些文件格式不对,可以用 --list-different 替代 --check,它会列出有问题的文件名,输出更直观:
yaml- run: npx prettier --list-different "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}"
GitLab CI
在 .gitlab-ci.yml 中添加:
yamlprettier: stage: test image: node:20-alpine script: - npm ci - npx prettier --check "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}" only: - merge_requests - main cache: key: ${CI_COMMIT_REF_SLUG} paths: - node_modules/
用 node:20-alpine 镜像比完整 Node 镜像小 5 倍以上,流水线启动更快。加上 cache 配置避免每次都全量安装依赖。
如果想在 GitLab 的 Code Quality 报告中展示 Prettier 错误,可以使用 @studiometa/prettier-formatter-gitlab 将输出转为 GitLab 可识别的格式。
Jenkins
在 Jenkinsfile 中添加阶段:
groovystage('Format Check') { steps { sh 'npm ci' sh 'npx prettier --check "src/**/*.{js,jsx,ts,tsx}"' } }
Bitbucket Pipelines
在 bitbucket-pipelines.yml 中添加:
yamlpipelines: pull-requests: '**': - step: name: Prettier Check image: node:20-alpine script: - npm ci - npx prettier --check "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}"
Prettier 配置文件示例
CI 检查的准确性依赖项目中有明确的 Prettier 配置。创建 .prettierrc:
json{ "semi": true, "singleQuote": true, "trailingComma": "es5", "printWidth": 100, "tabWidth": 2 }
同时创建 .prettierignore 排除不需要检查的内容:
shellnode_modules dist build coverage *.min.js package-lock.json
配置必须在本地和 CI 之间保持一致——这也是为什么 Prettier 要作为 devDependencies 安装而非全局安装,npm ci 会确保 CI 环境拿到和本地完全相同的版本。
Prettier 与 ESLint 的协作
Prettier 只管格式,ESLint 管代码质量,两者配合才是完整方案。核心原则是用 eslint-config-prettier 关闭 ESLint 中与 Prettier 冲突的规则:
bashnpm install --save-dev eslint-config-prettier
在 .eslintrc.js 中:
jsmodule.exports = { extends: [ 'eslint:recommended', 'prettier' // 必须放在最后,覆盖前面的格式相关规则 ] }
CI 中可以合并为一条检查:
yamlscript: - npm ci - npx eslint "src/**/*.{js,ts}" - npx prettier --check "src/**/*.{js,ts,json,css,md}"
Monorepo 场景的优化策略
在 Turborepo 或 Nx 管理的 monorepo 中,全量 npm ci + 全局 Prettier check 会非常慢。两个优化方向:
-
用 Turborepo 的 filter 定位变更包:
bashnpx turbo run format:check --filter=...[HEAD^]只检查本次提交影响到的包。
-
用 changesets 圈定范围:在 CI 中先用
git diff找出变更的包目录,再对对应目录执行 Prettier check。 -
Prettier 的
--cache选项(Prettier 3.1+ 支持):只检查未缓存的文件,对大型仓库效果显著:bashnpx prettier --check --cache "src/**/*.{js,ts}"缓存默认写入
node_modules/.cache/prettier,CI 中记得把这个目录加入缓存配置。
CI 检查失败怎么办
当 CI 报告格式不一致时,最快的修复方式是在本地执行:
bashnpx prettier --write "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}"
如果频繁出现格式不一致,排查以下几点:
- Prettier 版本不一致:检查
package.json中的版本,确保本地和 CI 的npm ci安装的是同一个版本 - 编辑器格式化插件冲突:VS Code 中可能同时有多个格式化扩展在生效,在设置中指定 Prettier 为默认格式化器
- .editorconfig 与 .prettierrc 冲突:两者同时存在时 Prettier 优先,但建议统一到 .prettierrc 中管理
核心要点总结
- 本地 Git Hook 做即时反馈,CI 流水线做兜底保障,两者缺一不可
--check模式用于 CI,--write模式用于本地修复,不要在 CI 中用--write- 用
npm ci代替npm install保证依赖版本一致性 - Prettier 与 ESLint 配合时,eslint-config-prettier 必须放在 extends 最后
- Monorepo 项目用 filter 或
--cache缩小检查范围,避免全量扫描拖慢流水线