前端2026年5月30日 10:11
Prettier 支持哪些语言和文件类型?Prettier 原生支持 JavaScript、TypeScript、JSX、TSX、CSS、SCSS、Less、HTML、Vue、Angular、JSON、YAML、Markdown、MDX、GraphQL 等常见前端和文档格式。Java、PHP、Ruby、XML 等也可以通过插件或社区解析器支持。判断能不能格式化,关键看 Prettier 是否有对应 parser。
## 追问
### Prettier 原生支持哪些文件?
常见有 `.js`、`.jsx`、`.ts`、`.tsx`、`.css`、`.scss`、`.less`、`.html`、`.vue`、`.json`、`.yaml`、`.md`、`.mdx`、`.graphql`。
### 插件支持和原生支持有什么区别?
原生支持开箱即用;插件支持需要额外安装包,团队里要统一依赖版本,否则 CI 和本地结果可能不一致。
### Prettier 怎么判断用哪个解析器?
通常根据扩展名自动选择 parser。识别不了时,可以用 `overrides` 指定 parser。
## 写段代码
```json
{"overrides":[{"files":"*.vue","options":{"parser":"vue"}}]}
```标签
Prettier
Prettier 是一款流行的代码格式化工具。 它支持的语言相当多。 它很纯粹,就一个代码格式化工具,并不会做代码质量的检查。 Prettier 会强制使用统一的代码风格,原理就是解析语言生成AST 抽象语法树,然后用自己的一套风格写回到文件。

前端5月28日 07:28
Prettier 与其他代码格式化工具有什么区别?如何选择?## Prettier 和 ESLint 有什么本质区别?
Prettier 是代码**格式化工具**,ESLint 是代码**质量检查工具**,二者不是替代关系而是互补关系。
核心区别在于工作原理:Prettier 将代码解析为 AST(抽象语法树),然后按照自己的规则重新输出,保证同样的输入永远得到同样的输出;ESLint 则基于规则引擎逐行扫描代码,检测潜在的错误和反模式。
实际项目中标准做法是两者结合:用 `eslint-config-prettier` 关闭 ESLint 中与格式化重叠的规则,让 Prettier 完全负责格式化(缩进、换行、引号风格),ESLint 专注代码质量(未使用变量、潜在 bug、最佳实践)。
```json
// .eslintrc.json
{
"extends": ["eslint:recommended", "prettier"],
"plugins": ["prettier"]
}
```
## Prettier 相比 Beautify、Standard.js 的优势在哪?
**vs Beautify**: Beautify 基于正则匹配做格式化,不具备 AST 解析能力,对复杂语法结构(如嵌套的三元表达式、链式调用)的格式化效果差,且输出不确定——同一份代码多次格式化可能产生不同结果。Prettier 基于 AST 重新打印代码,输出完全确定性,这是团队协作的基础。
**vs Standard.js**: Standard.js 是"零配置"的代名词,但它不允许任何自定义——分号必须有或必须没有,没有中间地带。Prettier 同样开箱即用,但保留了少量关键配置(单引号/双引号、分号、行宽等),适合需要一定灵活性的团队。
| 维度 | Prettier | Beautify | Standard.js |
|------|----------|----------|-------------|
| 解析方式 | AST | 正则 | AST |
| 输出确定性 | 完全确定 | 不确定 | 完全确定 |
| 可配置性 | 少量关键选项 | 丰富 | 几乎为零 |
| 多语言支持 | JS/TS/CSS/HTML/JSON/MD | JS/CSS/HTML | JS/TS |
## Biome 等新一代工具会取代 Prettier 吗?
2026 年 Biome 成为最值得关注的替代方案。它用 Rust 编写,将格式化和 lint 合并为一个工具,在大型 monorepo 中性能优势显著:10,000+ 文件的项目,格式化+检查不到 200ms,而 ESLint+Prettier 组合需要近 12 秒。
但 Prettier 短期内不会被取代,原因有三:
1. **生态成熟度**: Prettier 拥有大量编辑器插件、预提交钩子、CI 集成方案,Biome 生态仍在追赶
2. **插件体系**: Prettier 支持插件格式化额外语言(如 Java、Ruby、PHP),Biome 目前语言覆盖有限
3. **迁移成本**: 已有项目的 `.prettierrc` 配置和格式化基线,切换工具意味着大量 diff
**选择建议**: 新项目可以尝试 Biome,享受性能提升和简化配置;已有项目不必急于迁移,等 Biome 生态更成熟再说。
## Prettier 的 AST 重打印机制是什么意思?
这是理解 Prettier 行为的关键。Prettier 的工作流程:
1. **解析(Parse)**: 将源代码解析为 AST
2. **遍历(Traverse)**: 遍历 AST 节点
3. **打印(Print)**: 根据行宽限制和自身规则重新输出代码
这意味着 Prettier 不是"调整"你的代码,而是"重新生成"你的代码。你写的空行、多余括号、手动对齐——大部分都会被丢弃重写。
这也是为什么 Prettier 配置选项少:它不是逐条规则控制,而是整体重打印,只暴露行宽、缩进等顶层参数。这种设计牺牲了灵活性,换来了确定性。
## 实际项目中怎么配置 Prettier + ESLint?
完整的工程化配置分三步:
**第一步:安装依赖**
```bash
npm install -D prettier eslint eslint-config-prettier eslint-plugin-prettier
```
**第二步:配置文件**
```json
// .prettierrc
{
"semi": true,
"singleQuote": true,
"printWidth": 80,
"trailingComma": "es5"
}
```
```json
// .eslintrc.json
{
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
"env": { "es2024": true, "node": true }
}
```
`plugin:prettier/recommended` 做了三件事:加载 `eslint-plugin-prettier`(把 Prettier 规则作为 ESLint 规则运行)、加载 `eslint-config-prettier`(关闭 ESLint 格式化相关规则)、设置 `prettier/prettier` 为 error 级别。
**第三步:编辑器集成**
```json
// .vscode/settings.json
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
```
保存时先 Prettier 格式化,再 ESLint 自动修复,分工明确不冲突。
**第四步:Git 钩子自动化**
```bash
npm install -D husky lint-staged
npx husky init
echo "npx lint-staged" > .husky/pre-commit
```
```json
// package.json
{
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"],
"*.{css,html,json,md}": ["prettier --write"]
}
}
```
提交时自动格式化和检查,不合格的代码进不了仓库。
## Prettier 有哪些已知局限?
**配置不够灵活**: 行宽以内无法手动换行,`printWidth: 80` 时超过 80 字符的链式调用会被强制换行,即使你手动排列得更易读。这是"确定性"的代价——不允许个人偏好覆盖工具判断。
**大项目性能瓶颈**: Prettier 是单线程的,超大型项目全量格式化耗时较长。应对方式是用 `lint-staged` 只格式化变更文件,或引入缓存。
**版本升级可能产生 diff**: Prettier 的格式化结果在不同大版本间可能有差异,团队必须锁定版本号,升级时全量格式化会产生大量无意义 diff。
## 面试追问:什么时候不该用 Prettier?
三种场景下 Prettier 不是最佳选择:
1. **遗留大型项目**: 全量格式化会产生数千行 diff,干扰 code review,建议渐进式引入(只格式化新文件或变更文件)
2. **需要精细控制格式的场景**: 如代码生成器输出、教学材料中特意安排的缩进,Prettier 的重打印会破坏这些刻意格式
3. **纯 Python 项目**: Python 有 Black,设计理念与 Prettier 一致但针对 Python 语法优化,混用 Prettier 反而增加复杂度
前端5月28日 07:26
如何在 CI/CD 中集成 Prettier 做代码格式检查?## 为什么要用 Prettier 拦截代码格式问题
代码格式不一致是团队协作中最容易引发无意义争论的问题。Prettier 通过"零配置强制统一"的思路消除了这类争议,但仅靠开发者自觉运行 Prettier 并不可靠——有人会忘记格式化,有人会选择性忽略。把 Prettier 检查嵌入 CI/CD 流水线,是保证代码库格式一致性的最后防线。
推荐的两层防护策略:本地 Git Hook 做即时拦截 + CI 流水线做兜底检查。前者让开发者在提交前就能发现问题,后者防止绕过 Hook 的代码进入主分支。
## 本地拦截:Git Hooks 配置
### Husky + lint-staged 方案
这是目前最主流的方案,lint-staged 的核心优势是只格式化本次提交涉及的文件,不会全量扫描,提交速度有保障。
1. **安装依赖**
```bash
npm install --save-dev husky lint-staged prettier
npx husky install
npm pkg set scripts.prepare="husky install"
```
2. **配置 lint-staged**
在 `package.json` 中添加:
```json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier --write"
],
"*.{json,css,scss,md}": [
"prettier --write"
]
}
}
```
分开配置的好处是后续可以为 JS/TS 文件加入 ESLint 检查,而不影响纯样式或文档文件。
3. **创建 pre-commit Hook**
```bash
npx 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`:
```yaml
name: 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` 中添加:
```yaml
prettier:
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` 中添加阶段:
```groovy
stage('Format Check') {
steps {
sh 'npm ci'
sh 'npx prettier --check "src/**/*.{js,jsx,ts,tsx}"'
}
}
```
### Bitbucket Pipelines
在 `bitbucket-pipelines.yml` 中添加:
```yaml
pipelines:
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` 排除不需要检查的内容:
```
node_modules
dist
build
coverage
*.min.js
package-lock.json
```
**配置必须在本地和 CI 之间保持一致**——这也是为什么 Prettier 要作为 devDependencies 安装而非全局安装,`npm ci` 会确保 CI 环境拿到和本地完全相同的版本。
## Prettier 与 ESLint 的协作
Prettier 只管格式,ESLint 管代码质量,两者配合才是完整方案。核心原则是**用 eslint-config-prettier 关闭 ESLint 中与 Prettier 冲突的规则**:
```bash
npm install --save-dev eslint-config-prettier
```
在 `.eslintrc.js` 中:
```js
module.exports = {
extends: [
'eslint:recommended',
'prettier' // 必须放在最后,覆盖前面的格式相关规则
]
}
```
CI 中可以合并为一条检查:
```yaml
script:
- npm ci
- npx eslint "src/**/*.{js,ts}"
- npx prettier --check "src/**/*.{js,ts,json,css,md}"
```
## Monorepo 场景的优化策略
在 Turborepo 或 Nx 管理的 monorepo 中,全量 `npm ci` + 全局 Prettier check 会非常慢。两个优化方向:
1. **用 Turborepo 的 filter 定位变更包**:
```bash
npx turbo run format:check --filter=...[HEAD^]
```
只检查本次提交影响到的包。
2. **用 changesets 圈定范围**:在 CI 中先用 `git diff` 找出变更的包目录,再对对应目录执行 Prettier check。
3. **Prettier 的 `--cache` 选项**(Prettier 3.1+ 支持):只检查未缓存的文件,对大型仓库效果显著:
```bash
npx prettier --check --cache "src/**/*.{js,ts}"
```
缓存默认写入 `node_modules/.cache/prettier`,CI 中记得把这个目录加入缓存配置。
## CI 检查失败怎么办
当 CI 报告格式不一致时,最快的修复方式是在本地执行:
```bash
npx 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` 缩小检查范围,避免全量扫描拖慢流水线前端5月28日 07:26
Prettier 命令行工具有哪些常用命令和选项?## Prettier 命令行工具有哪些常用命令和选项?
Prettier 的命令行工具是日常开发中格式化代码的核心手段,掌握常用命令和关键选项不仅能提升开发效率,也是前端工程化面试中的高频考点。
### 核心命令
**格式化文件:`--write`**
`--write` 是最常用的选项,直接修改文件为格式化后的内容:
```bash
# 格式化单个文件
npx prettier --write src/index.ts
# 格式化整个项目
npx prettier --write .
```
面试追问:`--write` 会先写入临时文件再原子替换原文件,避免写入中断导致文件损坏。
**检查格式:`--check`**
`--check` 只检查文件是否符合 Prettier 格式,不修改文件。文件不合规时退出码为 1,因此广泛用于 CI 流水线:
```bash
npx prettier --check "src/**/*.{js,ts}"
# 在 CI 中使用
npx prettier --check . || echo "存在未格式化的文件"
```
**列出差异文件:`--list-different`**
`--list-different`(简写 `-l`)只输出格式不一致的文件路径,不输出格式化内容,适合脚本处理:
```bash
npx prettier --list-different "src/**/*.js"
```
与 `--check` 的区别:`--check` 会输出详细的人类可读信息,`--list-different` 只输出文件路径,更便于后续管道处理。
**查看差异:`--diff`**
`--diff` 输出格式化前后的 diff 对比,方便在不修改文件的前提下预览变更:
```bash
npx prettier --diff src/app.ts
```
### 配置与忽略
**指定配置文件:`--config`**
默认 Prettier 会沿目录向上查找 `.prettierrc` 等配置文件,使用 `--config` 可指定自定义配置:
```bash
npx prettier --config .prettierrc.staging.json --write src/
```
**查找配置路径:`--find-config-path`**
输出给定文件实际使用的配置文件路径,用于排查配置生效问题:
```bash
npx prettier --find-config-path src/index.ts
# 输出: /project/.prettierrc
```
**忽略文件:`--ignore-path`**
默认使用 `.prettierignore`,可通过 `--ignore-path` 指定自定义忽略文件:
```bash
npx prettier --ignore-path .gitignore --write .
```
将 `.gitignore` 复用为忽略规则是一个实用技巧。
**忽略未知文件类型:`--ignore-unknown`**
格式化整个项目时,遇到 Prettier 不支持的文件类型默认会报错,加上此选项会自动跳过:
```bash
npx prettier --write --ignore-unknown .
```
### 缓存与性能
**启用缓存:`--cache`**
大型项目格式化耗时较长,`--cache` 通过缓存未变更文件的格式化结果显著提升速度:
```bash
npx prettier --write --cache "src/**/*.ts"
```
**缓存位置:`--cache-location`**
指定缓存文件的存储路径:
```bash
npx prettier --write --cache --cache-location .prettiercache src/
```
**缓存策略:`--cache-strategy`**
支持两种策略:
- `metadata`(默认):根据文件修改时间判断,速度快但不够精确
- `content`:根据文件内容哈希判断,更精确但稍慢
```bash
npx prettier --write --cache --cache-strategy content src/
```
### 输出控制
**输出到标准输出**
不加 `--write` 时,Prettier 将格式化结果输出到 stdout,不修改原文件:
```bash
npx prettier src/index.ts
```
**指定输出目录:`--out-dir`**
将格式化结果写入指定目录而非原文件,适合生成格式化副本:
```bash
npx prettier "src/**/*.js" --out-dir formatted/
```
**标准输入:`--stdin-filepath`**
从标准输入读取代码时,Prettier 无法判断文件类型,通过此选项指定虚拟路径:
```bash
echo "const x=1" | npx prettier --stdin-filepath index.ts
```
这在编辑器集成和管道场景中非常关键。
### 与工程化工具集成
**在 package.json 中配置脚本**
```json
{
"scripts": {
"format": "prettier --write "src/**/*.{js,ts,json,css,md}"",
"format:check": "prettier --check "src/**/*.{js,ts,json,css,md}"",
"format:all": "prettier --write --ignore-unknown ."
}
}
```
**配合 lint-staged 只格式化暂存文件**
```json
{
"lint-staged": {
"*.{js,ts,css,md}": "prettier --write"
}
}
```
这样配合 husky 的 pre-commit 钩子,每次提交只格式化本次变更的文件,避免全量格式化带来的提交噪音。
**在 CI 中强制格式检查**
```yaml
- name: Check formatting
run: npx prettier --check .
```
`--check` 在文件不合规时返回退出码 1,CI 流水线会因此失败,确保仓库中不会混入未格式化的代码。
### 调试命令
**调试检查:`--debug-check`**
格式化文件并检查格式化是否改变了 AST,用于排查 Prettier 自身的 bug。不能与 `--write` 同时使用:
```bash
npx prettier --debug-check src/index.ts
```
**查看帮助与版本**
```bash
npx prettier --help
npx prettier --version
```
Prettier 命令行工具在日常开发中主要用于格式化和检查,在工程化体系中则通过 `--check` 与 CI 集成、通过 `--list-different` 与 lint-staged 配合,理解每个命令的应用场景比记住参数更重要。前端5月28日 07:25
如何在 Monorepo 项目中配置和使用 Prettier?## 核心答案
在 Monorepo 中配置 Prettier,关键是**统一配置 + 分包覆盖 + 工具链集成**三步走:根目录放一份基础 `.prettierrc` 作为全局基准,通过共享配置包 `@org/prettier-config` 让各子项目继承,再用 `overrides` 按包定制差异规则,最后配合 Husky + lint-staged 在提交时自动格式化、Turborepo/Nx 在 CI 层做缓存检查。
## 根目录统一配置
最简单的方式是在 monorepo 根目录创建 `.prettierrc`:
```json
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80
}
```
Prettier 会从文件所在目录向上查找配置,子包如果自己没有 `.prettierrc`,就自动继承根目录的规则。这意味着只要根目录配置到位,大部分子包无需额外配置。
需要注意的是,如果子包自己也有 `.prettierrc`,它会**完全覆盖**根配置而不是合并。所以除非有必要,不要在子包里单独放配置文件。
## 共享配置包
当团队规模较大或 monorepo 包含多个独立发布的库时,推荐把 Prettier 配置抽成 npm 包:
```javascript
// packages/prettier-config/index.js
module.exports = {
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: "es5",
printWidth: 80,
bracketSpacing: true,
arrowParens: "always",
};
```
```json
// packages/prettier-config/package.json
{
"name": "@my-org/prettier-config",
"version": "1.0.0",
"main": "index.js"
}
```
在各子包中引用:
```json
{
"prettier": "@my-org/prettier-config"
}
```
共享配置包的优势在于版本可控——改一处发布新版本,所有依赖它的子包 `npm update` 即可同步。对于使用 pnpm workspace 的项目,直接用 `workspace:*` 协议引用,无需发布到外部 registry。
## 分包差异化配置(overrides)
有些子包需要不同的格式化规则,比如 UI 库希望更宽的 `printWidth`,而后端服务保持 80 列。用 `overrides` 字段实现:
```json
{
"semi": true,
"singleQuote": true,
"printWidth": 80,
"overrides": [
{
"files": "packages/ui/**/*",
"options": {
"printWidth": 100
}
},
{
"files": "packages/server/**/*",
"options": {
"printWidth": 80
}
},
{
"files": "packages/docs/**/*.md",
"options": {
"proseWrap": "always",
"printWidth": 90
}
}
]
}
```
`overrides` 是在根配置基础上**增量覆盖**,不会丢失未显式指定的规则。这比在每个子包单独放 `.prettierrc` 更容易维护。
## .prettierignore 配置
很多教程忽略了 `.prettierignore`,但它在 monorepo 中非常关键。典型的忽略规则:
```
node_modules
dist
build
coverage
.next
.turbo
*.min.js
*.min.css
pnpm-lock.yaml
package-lock.json
```
不配 `.prettierignore` 会导致 `prettier --write` 扫描 `node_modules` 和构建产物,既浪费时间又可能报错。尤其在 monorepo 中,子包的 `dist` 目录层级深,手动排除不现实,需要用通配符一次搞定。
## 与 ESLint 的冲突解决
Prettier 和 ESLint 同时存在时,格式化规则会冲突。比如 ESLint 要求尾逗号,Prettier 又删掉尾逗号,来回打架。解决方案分两步:
**第一步**:安装 `eslint-config-prettier`,它关闭所有与 Prettier 冲突的 ESLint 规则:
```bash
pnpm add -wD eslint-config-prettier
```
```javascript
// .eslintrc.js
module.exports = {
extends: [
"eslint:recommended",
// 其他配置...
"prettier" // 必须放最后,覆盖前面的格式化规则
]
};
```
**第二步**(可选):如果想在 ESLint 中实时报告格式问题,安装 `eslint-plugin-prettier`:
```bash
pnpm add -wD eslint-plugin-prettier
```
```javascript
module.exports = {
plugins: ["prettier"],
rules: {
"prettier/prettier": "error"
}
};
```
不过在 monorepo 中,更推荐的做法是**分离职责**:ESLint 只管代码质量,Prettier 只管格式,不要把 Prettier 嵌入 ESLint。这样运行更快,调试也更清晰。
## Husky + lint-staged 自动格式化
提交时自动格式化是 monorepo 的标配实践:
```bash
pnpm add -wD husky lint-staged
pnpm exec husky init
```
```json
// package.json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["prettier --write"],
"*.{json,css,md}": ["prettier --write"]
}
}
```
```bash
# .husky/pre-commit
pnpm exec lint-staged
```
这样每次 `git commit` 只会格式化**暂存区的文件**,而不是整个项目。对于 monorepo 来说,增量处理比全量扫描快得多。
如果使用 pnpm workspace,可以把 lint-staged 配置放在根目录,它会自动根据修改文件的路径匹配对应规则。
## Turborepo 集成
Turborepo 的缓存机制能避免重复格式化检查:
```json
// turbo.json
{
"pipeline": {
"format": {
"outputs": []
},
"format:check": {
"outputs": []
}
}
}
```
```json
// 根 package.json
{
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
```
`outputs` 设为空数组是因为格式化不产生构建产物,Turborepo 只需要根据输入文件的变化判断是否需要重新执行。
实际项目中,`format:check` 通常放在 CI 里,而 `format` 在本地开发时使用。Turborepo 会缓存未变更文件的结果,二次运行几乎零耗时。
## Nx 集成
Nx 对 Prettier 有专门的 executor 支持:
```json
{
"targets": {
"format": {
"executor": "@nx/vite:format",
"options": {
"write": true
}
}
}
}
```
Nx 的优势在于**受影响项目检测**——只格式化当前提交影响到的子包:
```bash
nx format:check --projects=tag:scope:ui
nx format:write --projects=tag:scope:ui
```
这在大型 monorepo 中比 `prettier --write .` 高效很多。
## Lerna 集成
Lerna 的 `--scope` 选项可以针对特定子包执行格式化:
```bash
lerna exec --scope @my-org/ui -- prettier --write "src/**/*.js"
lerna exec --scope @my-org/core -- prettier --check "src/**/*.{ts,tsx}"
```
Lerna 7 之后去除了内置的 `lerna run` 对 Prettier 的特殊处理,推荐直接在子包的 `package.json` 里加 `format` 脚本,然后用 `lerna run format` 批量执行。
## 性能优化
**增量格式化**——只处理 Git 暂存区中的变更文件:
```bash
git diff --name-only --diff-filter=ACM HEAD | grep -E '\.(js|ts|tsx)$' | xargs prettier --write
```
**并行处理**——多核同时跑,适合项目文件数过万的场景:
```bash
find . -name "*.ts" -not -path "*/node_modules/*" | parallel -j 4 prettier --write
```
**缓存机制**——Prettier 3.0 原生支持缓存:
```bash
prettier --write --cache --cache-strategy content "src/**/*.ts"
```
`--cache-strategy content` 基于文件内容哈希判断是否需要重新格式化,比默认的 `metadata` 策略更准确。首次运行生成缓存,后续未修改的文件直接跳过。
**真实场景**:在一个 200+ 子包的 monorepo 中,全量 `prettier --check .` 需要 45 秒。加上缓存后,二次运行降至 3 秒以内。配合 lint-staged 只处理暂存文件,提交时的格式化检查几乎无感。
## CI/CD 集成
在 GitHub Actions 中配置格式化检查:
```yaml
name: Format Check
on: [push, pull_request]
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run format:check
```
关键点:CI 中必须用 `--check`(只检查不修改),而不是 `--write`。如果格式不合格,CI 直接报错,开发者本地 `format` 后重新提交。
如果用 Turborepo,可以配合缓存进一步加速:
```yaml
- uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
- run: npx turbo format:check
```
## 常见问题排查
**问题1:子包格式化规则不生效**
检查子包目录下是否有自己的 `.prettierrc`。如果存在,它会完全覆盖根配置。删除子包的 `.prettierrc`,改用根目录的 `overrides` 来定制规则。
**问题2:Prettier 和 ESLint 反复修改同一行**
确认 `eslint-config-prettier` 放在了 `extends` 数组的**最后一位**。如果放在前面,后续配置会重新开启被关闭的规则。
**问题3:CI 中格式检查通过但本地不通过(或反过来)**
通常是 Prettier 版本不一致导致的。在 monorepo 根目录统一安装 Prettier,子包不要单独安装。用 `pnpm ls prettier` 检查是否有多个版本。
**问题4:格式化速度过慢**
按优先级排查:1) 检查 `.prettierignore` 是否正确排除了 `node_modules` 和构建产物;2) 启用 `--cache`;3) 用 lint-staged 只处理变更文件;4) 考虑并行处理。
## 追问
**为什么推荐共享配置包而不是根目录 .prettierrc?**
根目录配置对纯内部 monorepo 足够。但如果某些子包会独立发布到 npm,它们脱离 monorepo 上下文后就失去了根配置。共享配置包作为 npm 依赖,无论在不在 monorepo 中都能生效。
**Prettier 3.0 有哪些影响 monorepo 的变化?**
最大的变化是原生缓存支持(`--cache`)和 ESM 配置文件支持(`prettier.config.mjs`)。缓存对大型 monorepo 的性能提升显著。ESM 配置则允许在配置文件中动态导入其他模块,比如根据环境变量切换规则。前端5月28日 07:24
Prettier 与 ESLint 有什么区别?如何协作使用?## Prettier 与 ESLint 有什么区别?如何协作使用?
前端项目中,Prettier 和 ESLint 是最常搭配使用的两个工具,但它们的职责完全不同。理解各自的定位,才能正确配置和协作使用。
### Prettier 和 ESLint 各自负责什么
**Prettier 是代码格式化工具**,只关心代码长什么样:
- 统一缩进、引号、分号、换行等风格
- 解析代码生成 AST 后重新输出,确保格式完全一致
- 配置项很少(约20个),设计理念是"别吵了,就用这个"
- 支持 JS/TS/CSS/HTML/JSON/Markdown 等多种语言
**ESLint 是代码质量检查工具**,关心代码有没有问题:
- 检测未使用变量、潜在错误、不安全的写法
- 执行团队约定的编码规范(如禁用 var、要求 ===)
- 拥有数千条可配置规则和丰富的插件生态
- 仅针对 JavaScript/TypeScript
核心区别一句话: **Prettier 管"好不好看",ESLint 管"对不对"**。
### 为什么不能只用一个
ESLint 虽然也有格式化规则(如缩进、引号),但能力有限且配置复杂。Prettier 的格式化效果更一致、覆盖语言更多,且几乎不需要团队争论配置。
反过来,Prettier 完全不做代码质量检查,漏掉未使用变量、错误逻辑等问题会埋下隐患。
两者结合是当前前端工程的标准做法。
### 协作配置(ESLint Flat Config)
从 ESLint v9 开始,官方推荐使用 Flat Config(`eslint.config.js`)替代旧版 `.eslintrc`。新配置方式如下:
**安装依赖:**
```bash
npm install --save-dev eslint prettier eslint-config-prettier
```
**配置 eslint.config.js:**
```javascript
import js from "@eslint/js";
import prettierConfig from "eslint-config-prettier";
export default [
js.configs.recommended,
prettierConfig, // 必须放在最后,关闭与 Prettier 冲突的规则
{
rules: {
"no-unused-vars": "warn",
"prefer-const": "error",
},
},
];
```
**配置 .prettierrc:**
```json
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}
```
关键点: `eslint-config-prettier` 必须放在配置数组最后,它会关闭所有与 Prettier 冲突的 ESLint 格式化规则,让 Prettier 独占格式化职责。
### 旧版配置方式(.eslintrc)
如果项目仍在使用旧版配置,这样设置:
```javascript
// .eslintrc.js
module.exports = {
extends: [
"eslint:recommended",
"prettier", // 放在最后
],
};
```
### eslint-plugin-prettier 还需要吗
`eslint-plugin-prettier` 的作用是把 Prettier 的格式化结果作为 ESLint 规则来报告。Prettier 官方现在不再推荐这种方式,原因是:
- 它让 ESLint 承担了格式化职责,导致运行变慢
- 格式化问题被混在 ESLint 报错中,难以区分
- 推荐做法是让两者各自独立运行
### 编辑器集成
在 VS Code 中配置自动格式化,保存时同时生效:
```json
// .vscode/settings.json
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}
```
保存时先由 Prettier 格式化,再由 ESLint 修复代码质量问题,顺序正确无冲突。
### Git 提交时自动检查
配合 Husky 和 lint-staged,在提交代码时自动运行检查:
```bash
npm install --save-dev husky lint-staged
npx husky init
```
```json
// package.json
{
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"],
"*.{css,html,md,json}": ["prettier --write"]
}
}
```
```bash
# .husky/pre-commit
npx lint-staged
```
这样只有暂存的文件会被检查,既保证代码质量又不影响提交效率。
### 常见冲突与排查
| 问题 | 原因 | 解决方式 |
|------|------|----------|
| ESLint 报缩进/引号错误 | 格式化规则与 Prettier 冲突 | 确认 `eslint-config-prettier` 在 extends 最后 |
| Prettier 格式化后 ESLint 仍报错 | 质量规则报错,非格式问题 | 检查具体规则,质量规则应保留 |
| 保存时格式化不生效 | 编辑器未配置或扩展未安装 | 检查 VS Code 扩展和 settings.json |
可以用以下命令快速排查冲突规则:
```bash
npx eslint-config-prettier path/to/.eslintrc.js
```
### 执行顺序总结
实际运行时的正确顺序:
1. Prettier 先格式化代码(处理风格)
2. ESLint 再检查代码质量(处理逻辑)
3. 两者通过 `eslint-config-prettier` 隔离职责,互不干扰
掌握 Prettier 和 ESLint 的职责边界、正确配置方式以及常见冲突排查,是前端工程化基础设施的基本要求。前端5月27日 22:07
Prettier 支持哪些配置文件格式?## 答案
Prettier 支持以下配置文件格式,按查找优先级从高到低排列:
| 优先级 | 文件名 | 格式 |
|--------|--------|------|
| 1 | `package.json` 中 `prettier` 字段 | JSON |
| 2 | `.prettierrc` | JSON/YAML |
| 3 | `.prettierrc.json` | JSON |
| 4 | `.prettierrc.json5` | JSON5 |
| 5 | `.prettierrc.yml` / `.prettierrc.yaml` | YAML |
| 6 | `.prettierrc.toml` | TOML |
| 7 | `.prettierrc.js` / `.prettierrc.mjs` | JS(ESM) |
| 8 | `.prettierrc.cjs` | JS(CJS) |
| 9 | `prettier.config.js` / `prettier.config.mjs` | JS(ESM) |
| 10 | `prettier.config.cjs` | JS(CJS) |
Prettier 3.5+ 还支持 `.prettierrc.ts` / `prettier.config.ts`(TypeScript 格式),适合 TS 项目直接复用类型。
**选哪个?** 小项目用 `.prettierrc.json`,简洁无歧义,编辑器能做 JSON Schema 校验;需要注释或动态逻辑时用 `.prettierrc.js`;TS 项目可考虑 `.prettierrc.ts`。
```json
// .prettierrc.json — 最常用
{
"printWidth": 80,
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"endOfLine": "lf"
}
```
```javascript
// .prettierrc.js — 需要注释时
module.exports = {
printWidth: 80, // 每行最大字符数
tabWidth: 2, // 缩进空格数
semi: true, // 行尾分号
singleQuote: true, // 单引号
trailingComma: "es5",
endOfLine: "lf",
};
```
## 配置解析机制
Prettier 从**被格式化文件所在目录**开始向上搜索配置文件,直到项目根目录,不支持全局配置,确保不同机器行为一致。如果同时存在 `.editorconfig`,Prettier 会将其作为基础配置,但 `.prettierrc` 中的选项优先。
## overrides 按文件类型定制
```json
{
"semi": true,
"overrides": [
{
"files": ["*.md", "*.json"],
"options": { "tabWidth": 4 }
}
]
}
```
## .prettierignore
类似 `.gitignore`,排除不需要格式化的文件:
```
node_modules
dist
*.min.js
```
## 追问
**Q: .prettierrc 和 .prettierrc.json 有什么区别?**
没有本质区别。`.prettierrc` 优先级更高,Prettier 会先尝试按 JSON 解析,失败则尝试 YAML。`.prettierrc.json` 只按 JSON 解析,语义更明确,编辑器也能做 schema 校验。
**Q: Prettier 配置和 ESLint 冲突怎么办?**
安装 `eslint-config-prettier` 关闭 ESLint 中与 Prettier 冲突的规则即可。不要两边重复定义同一规则。
**Q: 为什么不推荐在 package.json 中配置?**
`package.json` 的 `prettier` 字段容易被忽略,且该文件本身体积大、职责多,配置混在一起不利于维护和代码审查。前端5月27日 22:04
Prettier 插件有哪些?如何开发自定义插件?## 直接回答
Prettier 支持两类插件:**语言解析器插件**(为新语言提供格式化能力)和**格式化增强插件**(扩展现有语言的格式化行为)。开发自定义插件需实现三个核心部分:`languages`(语言定义)、`parsers`(解析器,文本→AST)、`printers`(打印器,AST→格式化文本)。
## Prettier 插件分类
**语言解析器插件** — 让 Prettier 支持新语言:
- `@prettier/plugin-php`、`@prettier/plugin-ruby`、`@prettier/plugin-pug`
**格式化增强插件** — 对已有语言做额外处理:
- `prettier-plugin-organize-imports`:自动排序 import
- `prettier-plugin-tailwindcss`:Tailwind 类名排序
- `prettier-plugin-sort-json`:JSON 键排序
安装后在 `.prettierrc` 的 `plugins` 数组中声明即可。Prettier 也会自动加载 `node_modules` 下匹配 `prettier-plugin-*` 或 `@scope/prettier-plugin-*` 的包。
## 如何开发自定义插件
一个完整的插件至少导出 `languages`、`parsers`、`printers`:
```javascript
// my-prettier-plugin/index.js
module.exports = {
languages: [
{
name: "MyLang",
parsers: ["mylang-parse"],
extensions: [".mylang"],
},
],
parsers: {
"mylang-parse": {
parse: (text) => {
// 将源码文本解析为 AST
// 可借助第三方解析器(如 babel, tree-sitter 等)
return customParse(text);
},
astFormat: "mylang-ast",
locStart: (node) => node.start,
locEnd: (node) => node.end,
},
},
printers: {
"mylang-ast": {
print: (path, options, print) => {
// 将 AST 节点转换为 Prettier Doc 对象
// Doc 是 Prettier 的中间表示,支持换行、缩进等
const node = path.getValue();
// 用 concat/line/hardline 等构建输出
},
},
},
};
```
**开发要点:**
- `parse` 函数的输入是源码字符串,返回 AST 对象
- `locStart`/`locEnd` 告诉 Prettier 每个 AST 节点的位置,用于错误定位
- `print` 函数返回 Doc 对象,用 `concat`、`hardline`、`indent` 等 API 拼接格式化输出
- 如果只想对已有语言做预处理,只需在 parser 中实现 `preprocess` 函数,无需写完整 parser/printer
**调试方式:** 运行 `prettier --plugin ./my-prettier-plugin --debug-print-doc file.mylang` 可查看生成的 Doc 结构。
## 面试追问方向
1. **如果只想在格式化前对代码做预处理(如删除注释),怎么实现?** — 在对应 parser 中实现 `preprocess` 函数即可,不需要自定义整个 parser/printer 链路。
2. **Prettier 的 Doc 是什么?** — Prettier 内部的中间表示,类似虚拟 DOM。`print` 返回 Doc 而非字符串,Prettier 再根据行宽等配置将 Doc "渲染"为最终输出,这样能自动处理换行和缩进。
3. **插件和 Prettier 内置语言支持的区别?** — 内置语言是 Prettier 核心代码的一部分,性能和兼容性更优;插件是独立模块,更新节奏自由但需自行维护与 Prettier 版本的兼容。前端5月27日 22:04
使用 Prettier 时常见的问题有哪些?如何解决?## Prettier 配置不生效怎么办?
修改 `.prettierrc` 后格式化无变化,是最常见的坑。排查顺序:先用 `prettier --find-config-path <file>` 确认实际加载的配置文件,可能被上层目录的配置覆盖;再检查 JSON 语法是否合法(多余逗号是最常见的错误);最后重启编辑器,VS Code 会缓存配置。
多配置文件共存时,Prettier 按 `.prettierrc` > `.prettierrc.json` > `.prettierrc.yml` > `prettier.config.js` 的顺序查找,找到一个就停止。用 `--config` 显式指定可以彻底消除歧义。
> **追问**: `.prettierignore` 和 `.gitignore` 的区别是什么? — `.prettierignore` 只控制 Prettier 忽略哪些文件,不影响 Git;`.gitignore` 不被 Prettier 自动读取,除非用 `--ignore-path .gitignore` 显式指定。
## 如何忽略特定文件的格式化?
三种方式,适用场景不同:
- **项目级忽略**: `.prettierignore` 文件,语法与 `.gitignore` 一致,适合忽略 `dist/`、`vendor/` 等目录
- **行内忽略**: `// prettier-ignore` 注释,只忽略紧跟的下一行
```javascript
// prettier-ignore
const matrix = [
[1, 2, 3],
[4, 5, 6],
];
```
- **部分规则覆盖**: `overrides` 字段,为特定文件类型设置不同规则
```json
{
"overrides": [
{
"files": "*.md",
"options": { "proseWrap": "always" }
}
]
}
```
> **追问**: `// prettier-ignore` 能忽略整个文件吗? — 不能,它只作用于紧跟的下一个语法节点。要忽略整个文件,用 `.prettierignore`。
## Prettier 和 ESLint 冲突如何解决?
这是面试高频题。冲突根源:ESLint 有格式规则(如缩进、引号),Prettier 也有自己的规则,两者同时作用就会打架。
标准解法分两步:
1. 安装 `eslint-config-prettier`,它会关闭所有与 Prettier 冲突的 ESLint 规则
2. (可选) 安装 `eslint-plugin-prettier`,将 Prettier 格式问题作为 ESLint 错误报告
```javascript
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'plugin:prettier/recommended' // 必须放最后,否则会被前面的配置覆盖
]
};
```
`plugin:prettier/recommended` 已经包含了 `eslint-config-prettier`,不需要重复引入。`extends` 的顺序很关键——后面的配置会覆盖前面的,所以 Prettier 相关配置必须放末尾。
> **追问**: `eslint-plugin-prettier` 和 `prettier-eslint` 有什么区别? — `eslint-plugin-prettier` 让 ESLint 调用 Prettier;`prettier-eslint` 让 Prettier 的输出再过一遍 ESLint fix。前者是主流方案。
## 大项目格式化太慢怎么办?
Prettier 3.x 原生支持 `--cache`,只格式化变更的文件:
```bash
prettier --write --cache .
```
配合 `lint-staged` 只处理暂存文件更高效:
```json
{
"lint-staged": {
"*.{js,ts}": ["prettier --write"]
}
}
```
升级版本也有明显收益。Prettier 3 基于 ECMAScript 2024 重写了解析器,格式化速度比 2.x 快 2-3 倍。
> **追问**: `--cache` 的缓存存在哪里? — 默认存在 `node_modules/.cache/prettier`,可以通过 `--cache-location` 自定义路径。
## VS Code 中 Prettier 保存不格式化?
检查清单:
1. 安装了 Prettier 扩展
2. `settings.json` 中设置 `"editor.formatOnSave": true`
3. `"editor.defaultFormatter"` 设为 `"esbenp.prettier-vscode"`
4. 如果项目有多个 formatter,需要在 `"[javascript]"` 等语言设置中指定
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
```
多编辑器协作时,加 `.editorconfig` 统一基础缩进和换行符,避免 Tab/Space 之争。
## 团队版本不一致怎么处理?
锁定版本是最直接的办法:
```json
// package.json
{
"devDependencies": {
"prettier": "3.3.3" // 不用 ^ 前缀
}
}
```
团队用 `npm ci` 安装依赖,它会严格按 `package-lock.json` 安装,忽略 `node_modules` 中已有的版本。CI 环境同理,`npm ci` 比 `npm install` 更可靠。
升级 Prettier 大版本时,格式化结果可能变化。正确做法:单独开分支升级,确认无异常再合入主干,不要在功能分支中顺手升级。前端5月27日 22:03
Prettier 的 .prettierignore 怎么配置?有哪些常用规则和踩坑点?## .prettierignore 文件怎么写?
`.prettierignore` 放在项目根目录,语法和 `.gitignore` 完全一致。写好它才能放心跑 `prettier --write .`,否则会格式化不该动的文件。
```
node_modules
dist
build
coverage
*.min.js
*.min.css
package-lock.json
pnpm-lock.yaml
```
## Prettier 默认会忽略哪些文件?
不需要手动写,Prettier 自动忽略:
- 版本控制目录:`.git`、`.svn`、`.hg`
- `node_modules`(除非显式加 `--with-node-modules`)
另外,Prettier **自动读取同目录下的 `.gitignore`**,所以 `.gitignore` 里已经排除的文件不需要在 `.prettierignore` 里重复写。
## 四种忽略模式怎么用?
**1. 目录忽略**
```
node_modules
**/dist
```
**2. 扩展名忽略**
```
*.min.js
*.min.css
*.d.ts
```
**3. 路径通配符**
```
src/**/*.generated.ts
!src/vendor/*.js
```
`!` 是否定模式,表示"前面忽略的里面,这条除外"。
**4. 行内忽略(prettier-ignore 注释)**
不想格式化某一段代码,在上方加注释:
```js
// prettier-ignore
const matrix = [
[1, 000, 000],
[0, 1, 000],
[0, 000, 1]
];
```
HTML 里用 `<!-- prettier-ignore -->`,Markdown 里用 `<!-- prettier-ignore -->`,CSS 里用 `/* prettier-ignore */`。每种文件类型都有对应的注释语法。
## CLI 相关的忽略参数有哪些?
- `--ignore-path .prettierignore.custom`:指定自定义 ignore 文件路径
- `--with-node-modules`:取消默认对 node_modules 的忽略
- `--list-different`(别名 `-l`):只列出不符合格式的文件名,CI 场景常用
```bash
# 用自定义 ignore 文件格式化
prettier --write --ignore-path .prettierignore.custom "src/**/*.js"
# CI 中检查是否有未格式化的文件
prettier --check "src/**/*.js"
```
## 常见踩坑
**ignore 规则写了不生效?** 检查文件是否放在项目根目录,语法是否和 `.gitignore` 一致。
**想格式化被忽略的文件?** 直接传绝对路径给 prettier,ignore 规则不拦截绝对路径。
**`.prettierignore` 和 `.gitignore` 规则冲突怎么办?** `.prettierignore` 优先级更高。如果 `.gitignore` 排除了某个文件,但 `.prettierignore` 没有排除,Prettier 仍会格式化它。