Prettier + ESLint 集成配置指南 — 以 Vue3 项目为例

Prettier + ESLint 集成配置指南 — 以 Vue3 项目为例

Jerome Xiong
Jerome Xiong

背景

在一个 Vue3 + Vite 项目中,同时使用 ESLint(代码质量检查)和 Prettier(代码格式化)时,两者的规则可能冲突。最典型的就是 ESLint 要求最大行长 80 字符,而 Prettier 默认也是 80——看起来一致,但一旦自定义其中一个就可能打架。

解决方案:用 ESLint 驱动 Prettier。通过 eslint-plugin-prettier 将 Prettier 的格式化规则作为 ESLint 的一条规则运行,再通过 eslint-config-prettier 关闭所有与 Prettier 冲突的 ESLint 原生风格规则。

本文以 qiyun_admin 项目的实际配置为例,完整说明集成方式和关键细节。


依赖安装

1npm install -D prettier eslint-plugin-prettier eslint-config-prettier

三个包的分工:

包 作用
prettier 格式化引擎
eslint-plugin-prettier 将 Prettier 作为 ESLint 的一条 rule 运行
eslint-config-prettier 关闭 ESLint 中与 Prettier 冲突的风格规则

如果项目中还没有 ESLint 和 Vue ESLint 支持,还需安装:

1npm install -D eslint @eslint/js eslint-plugin-vue globals

1. Prettier 配置 — .prettierrc.yaml

1# 箭头函数参数始终加括号
2arrowParens: always
3# JSX 右尖括号与最后一行属性同行
4bracketSameLine: true
5# 对象大括号内部首尾保留空格
6bracketSpacing: true
7# 换行符使用 LF (Unix/Linux/macOS 风格)
8endOfLine: lf
9# 自动格式化嵌入的代码(如 Markdown 和 HTML 内的代码)
10embeddedLanguageFormatting: auto
11# HTML 忽略空白敏感性,结合bracketSameLine: true
12htmlWhitespaceSensitivity: "ignore"
13# JSX 中使用单引号
14jsxSingleQuote: true
15# 一行最多字符数
16printWidth: 120
17# 对象属性引号仅在必要时添加
18quoteProps: as-needed
19# 行尾不使用分号
20semi: false
21# 使用单引号
22singleQuote: true
23# 每个缩进级别的空格数
24tabWidth: 2
25# 是否添加多余逗号 none|es5|all
26trailingComma: es5
27# 使用空格而不是制表符缩进
28useTabs: false
29# Vue 文件中 script 和 style 标签内的代码也进行缩进
30vueIndentScriptAndStyle: false

关键点:

  • printWidth: 120 — 项目使用的行宽是 120,比 Prettier 默认的 80 更宽松,适合 Vue 模板中较长的属性链。
  • useTabs: true — 使用 Tab 缩进,配合 tabWidth: 2 让 Tab 显示为 2 个空格宽度。
  • semi: false — 无分号风格。
  • trailingComma: 'none' — 不添加尾逗号,与 ES2017 以来允许尾逗号的趋势不同,这里是团队风格选择。

2. ESLint 配置 — eslint.config.mjs(Flat Config)

项目使用 ESLint 的 Flat Config(eslint.config.mjs,ESLint v9+ 默认格式),而非传统的 .eslintrc.*。

1import js from "@eslint/js";
2import prettierConfig from "eslint-config-prettier";
3import prettierPlugin from "eslint-plugin-prettier";
4import pluginVue from "eslint-plugin-vue";
5import globals from "globals";
6import vueParser from "vue-eslint-parser";
7
8export default [
9  // 基础推荐规则
10  js.configs.recommended,
11  // Vue 推荐规则
12  ...pluginVue.configs["flat/essential"],
13  // 注意:必须放在其他配置之后,以确保它能覆盖前面的风格规则
14  prettierConfig,
15  {
16    plugins: {
17      // 注册 prettier 插件
18      prettier: prettierPlugin,
19    },
20    languageOptions: {
21      ecmaVersion: 2020,
22      sourceType: "module",
23      // 对应 env: { browser: true, node: true, es6: true }
24      globals: {
25        ...globals.browser,
26        ...globals.node,
27        ...globals.es2021,
28        // 对应 env: { 'vue/setup-compiler-macros': true }
29        defineProps: "readonly",
30        defineEmits: "readonly",
31        defineExpose: "readonly",
32        withDefaults: "readonly",
33      },
34      parser: vueParser,
35    },
36    rules: {
37      // --- 业务逻辑规则---
38      "no-unused-vars": "off",
39      "no-useless-assignment": "off",
40      "no-console": "off",
41      "no-debugger": "warn",
42      "style/arrow-parens": ["error", "always"],
43
44      // --- Vue 特定规则---
45      "vue/no-unused-vars": "warn",
46      "vue/custom-event-name-casing": "off",
47      "vue/attributes-order": "off",
48      "vue/one-component-per-file": "off",
49      "vue/require-default-prop": "off",
50      "vue/multi-word-component-names": "off",
51
52      // --- Prettier 集成规则 ---
53      // 将 Prettier 格式问题作为 ESLint 错误抛出,统一编辑器反馈
54      "prettier/prettier": "error",
55    },
56  },
57  {
58    // 忽略文件 (对应 .eslintignore)
59    ignores: ["dist/**", "static/**", "build/**"],
60  },
61];

集成原理

  1. prettierConfig(即 eslint-config-prettier) — 必须放在 js.configs.recommended 和 pluginVue 配置之后。它会把所有与 Prettier 冲突的 ESLint 原生风格规则全部关闭。如果放反了顺序,样式规则会被后面的配置重新打开,等于没关。

  2. prettierPlugin(即 eslint-plugin-prettier) — 通过 'prettier/prettier': 'error' 将 Prettier 的格式化结果作为 ESLint 的一条规则执行。不再额外传入 endOfLine 选项,直接信任 .prettierrc.yaml 中的配置。如果团队跨平台遇到换行符冲突(Delete '␍' 错误),统一通过 .gitattributes 解决,见 FAQ。

  3. 为什么很多 Vue 风格规则设为 'off' — 这些规则(如 vue/max-attributes-per-line、vue/html-closing-bracket-newline 等)都与 Prettier 的 HTML/Vue 格式化能力重叠。Prettier 对 Vue template 的格式化已经处理了缩进、换行、属性排列,所以关闭 ESLint 侧的同功能规则,避免冲突。

Flat Config 与传统 .eslintrc 的差异注意点

如果你从传统配置迁移到 Flat Config:

项目 传统 .eslintrc.js Flat Config eslint.config.mjs
导出 module.exports = { ... } export default [ ... ](数组)
插件注册 plugins: ['prettier'] plugins: { prettier: prettierPlugin }
配置继承 extends: ['prettier'] 直接导入并展开到数组
Parser 配置 parser: 'vue-eslint-parser' parser: pluginVue.parsers.vue
忽略文件 .eslintignore ignores: ['dist/**']

3. 忽略规则 — .prettierignore

1dist/
2node_modules/
3build/
4static/
5public/
6*.min.js
7*.min.css
8*.map
9.gitignore
10.curosr/
11.trae/
12.idea/

与 ESLint 的 ignores 保持同步,确保构建产物和第三方文件不被格式化。


4. VS Code 配置 — 保存时自动格式化

在项目根目录创建 .vscode/settings.json:

1{
2  // 通过 codeActionsOnSave 触发 ESLint 修复(同时也触发 prettier/prettier)
3  "editor.codeActionsOnSave": {
4    "source.fixAll.eslint": "explicit"
5  },
6
7  // JS/TS/Vue 文件:Prettier 在保存时自动格式化
8  "[javascript]": {
9    "editor.defaultFormatter": "esbenp.prettier-vscode",
10    "editor.formatOnSave": true
11  },
12  "[typescript]": {
13    "editor.defaultFormatter": "esbenp.prettier-vscode",
14    "editor.formatOnSave": true
15  },
16  "[vue]": {
17    "editor.defaultFormatter": "esbenp.prettier-vscode",
18    "editor.formatOnSave": true
19  }
20}

为什么不设全局 editor.formatOnSave?

在一个项目中,不同语言可能由不同工具负责格式化:JS/TS/Vue 用 Prettier,CSS/PostCSS 用 Stylelint。全局 formatOnSave: true 会强制 Prettier 格式化所有文件,导致与 Stylelint 冲突。

正确的做法是通过 语言作用域 精确控制:只有明确设置了 [javascript]、[typescript]、[vue] 等语言的文件才由 Prettier 格式化,其余语言(CSS、Markdown 等)保持不动,让 Stylelint 等专用工具处理。

而 codeActionsOnSave 的 source.fixAll.eslint 全局生效不会造成冲突——ESLint 只分析它配置中覆盖的文件类型,不会触碰 CSS 等无关文件。prettier/prettier 规则也只在 ESLint 检查的文件范围内生效,双重保险但不越界。

需要安装 VS Code 扩展:


5. NPM Scripts

在 package.json 中添加:

1{
2  "scripts": {
3    "format": "prettier --write \"src/**/*.{js,ts,vue,css,scss,json,md}\"",
4    "lint": "eslint src/ --fix",
5    "lint:check": "eslint src/"
6  }
7}
  • npm run format — 手动格式化所有源码
  • npm run lint — ESLint 检查并修复(同时也修复 Prettier 问题)
  • npm run lint:check — 仅检查,不修复(用于 CI)

6. Husky + lint-staged(可选)— 提交前自动检查

仅有编辑器保存格式化还不够——总有人忘记安装扩展、或者直接用其他编辑器修改。Husky + lint-staged 可以在 git commit 时自动对暂存文件运行格式化与 ESLint 检查,把住最后一道关。

安装

1npm install -D husky lint-staged
2npx husky init

husky init 会在项目根目录创建 .husky/ 文件夹和 pre-commit hook。

配置

.husky/pre-commit

1npx lint-staged

这是 Husky v9 默认生成的 hook 文件,内容只有这一行。

Husky v9 注意:旧版本(v4/v5)需要在 package.json 中配置 "husky": { "hooks": {...} } 或使用 .huskyrc.js。v9 统一使用 .husky/ 目录下的 shell 文件,更直观、可版本控制。

package.json 添加 lint-staged 配置

1{
2  "lint-staged": {
3    "*.{js,ts,vue}": ["prettier --write", "eslint --fix"],
4    "*.{css,scss,json,md}": ["prettier --write"]
5  }
6}

工作流程:

1git add src/components/Button.vue
2  → git commit -m "feat: add button"
3    → Husky 触发 pre-commit hook
4      → lint-staged 读取暂存文件
5        → 匹配 *.vue → 运行 prettier --write → 运行 eslint --fix
6        → 格式化结果自动加入暂存区
7    → commit 成功(或失败并提示修复)

为什么不直接把 eslint --fix 作为唯一的 hook?

因为 Prettier 格式化在某些场景下会修改 ESLint 不会触碰的部分(比如 Markdown 换行、YAML 缩进)。先跑 prettier 再跑 eslint,确保两者都通过。

跳过 hook

1git commit --no-verify -m "紧急修复:跳过 lint"

只在万不得已时使用(如修复生产环境紧急 bug)。


7. 工作流程总结

1编辑代码
2  → Ctrl+S(或 Cmd+S)
3    → VS Code Prettier 格式化
4    → ESLint 运行 prettier/prettier 校验
5    → ESLint 报告/修复其他代码质量问题
6  → git commit
7    → Husky / lint-staged 再次校验(可选)

在编辑器层面,Prettier 负责"好不好看",ESLint 负责"对不对"。通过 eslint-plugin-prettier,两者在保存时一次性完成,互不打架。


常见问题

Q: Prettier 格式化的结果和 ESLint 的 fix 结果不一致?

A: 检查 eslint-config-prettier 是否放在了数组的最后(或至少在所有规则配置之后)。Flat Config 中数组顺序决定规则优先级,后面的覆盖前面的。

Q: prettier/prettier 报错 Delete '␍' (prettier/prettier)?

A: 这是换行符冲突。统一团队的 .gitattributes 来解决:* text=auto eol=lf。不再建议在 prettier/prettier 规则中加 endOfLine: 'auto' 覆盖,因为这样会隐藏项目本身的换行符配置问题,而 .gitattributes 是更根本的解决方案。

Q: 配置了项目 .vscode/settings.json,但保存时 Prettier 不生效?

A: 最常见原因:VS Code 用户设置(User Settings)的优先级高于工作区设置(Workspace Settings)。如果你之前在用户设置中强制指定了其他格式化器,会覆盖项目配置。

检查路径:

  • macOS:~/Library/Application Support/Code/User/settings.json
  • Linux:~/.config/Code/User/settings.json
  • Windows:%APPDATA%\Code\User\settings.json

打开用户设置 JSON,检查是否有以下配置覆盖了项目设置:

1{
2  // ❌ 全局指定了其他格式化器,会优先生效
3  "editor.defaultFormatter": "dbaeumer.vscode-eslint",
4
5  // ❌ 全局关闭了保存格式化
6  "editor.formatOnSave": false,
7
8  // ❌ 按语言覆盖了格式化器
9  "[javascript]": {
10    "editor.defaultFormatter": "dbaeumer.vscode-eslint"
11  },
12  "[vue]": {
13    "editor.defaultFormatter": "some-other-formatter"
14  }
15}

VS Code 设置优先级(从低到高):

1默认设置 < 用户设置 < 工作区设置 < 文件夹设置

逻辑上工作区设置(.vscode/settings.json)应该覆盖用户设置,但有两点例外:

  1. editor.defaultFormatter 的行为:如果用户设置的 [language] 作用域下指定了格式化器,而工作区设置只在顶层指定了 editor.defaultFormatter,前者会胜出。所以项目配置需要同时在语言作用域下设置,如上面第 4 节所示。
  2. 显式排除:用户设置中有 "settingsSync.ignoredSettings": [...] 不会同步某些设置,但本地仍生效。

排查步骤:

  1. 打开命令面板(Cmd+Shift+P),输入 >Developer: Inspect Editor Tokens and Scopes
  2. 右键点击编辑器状态栏的 Prettier 图标,查看当前文件正在使用哪个格式化器
  3. 或者查看 VS Code 输出面板(Output),选择 "Log (Window)",搜索 Formatter 相关日志

推荐做法:不要在用户设置中设置 editor.defaultFormatter,让每个项目通过 .vscode/settings.json 自行声明。用户设置只放个人偏好(主题、字体、键绑定等)。

Q: 不想让 ESLint 报 Prettier 错误,只想让 Prettier 独立工作?

A: 那就不要用 eslint-plugin-prettier,只保留 eslint-config-prettier(关掉冲突规则)。Prettier 通过编辑器格式化器独立运行。但这样格式化错误不会显示在 ESLint 的问题面板中。

Q: Flat Config 中插件导入报错 "Module not found"?

A: 确保所有 ESLint 相关依赖都已安装(eslint、eslint-plugin-vue、globals、@eslint/js、eslint-plugin-prettier、eslint-config-prettier)。Flat Config 使用 ESM 的 import 语法,不要用 require()。

  • 标题: Prettier + ESLint 集成配置指南 — 以 Vue3 项目为例
  • 作者: Jerome Xiong
  • 创建于: 2026-06-23 16:00
  • 链接: https://jeromexiong.github.io/2026/06/23/Web-前端/Prettier-ESLint-集成配置指南/
  • 版权声明:本文章采用 CC BY-NC-SA 4.0 进行许可。
评论