ESLint + Prettier 配置与规则

1. 后端视角看前端 lint

Java 里你可能用过:

前端对应:

Java 前端
Checkstyle + SpotBugs + PMD ESLint
Spotless / google-java-format Prettier
Maven checkstyle plugin pnpm lint / pnpm format
@SuppressWarnings // eslint-disable-next-line

一句话总结分工

两个工具各司其职,但规则会部分重叠——这是 80% 配置冲突的根源,下面会解决。


2. in4vue 已有配置

# package.json 已装
"eslint": "^10.3.0"
"@eslint/js"
"@vue/eslint-config-typescript"
"eslint-plugin-vue"
"eslint-config-prettier"
"eslint-plugin-prettier"
"prettier": "^3.8.3"
"typescript-eslint"
"vue-eslint-parser"
// package.json
"scripts": {
  "lint": "eslint . --fix",
  "format": "prettier --write \"src/**/*.{ts,vue,json,css,scss}\""
}

配置文件 eslint.config.js(ESLint 9+ 的扁平配置格式,不是旧的 .eslintrc.js)。


3. 扁平配置(Flat Config):ESLint 9+ 的新方式

老项目里的 .eslintrc.js / .eslintrc.json 是旧格式。ESLint 9 默认用扁平配置,一个 eslint.config.js 文件搞定:

// eslint.config.js
import js from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginVue from 'eslint-plugin-vue'
import prettierConfig from 'eslint-config-prettier'
import vueParser from 'vue-eslint-parser'

export default [
  // 1. 基础规则
  js.configs.recommended,
  ...tseslint.configs.recommended,
  ...pluginVue.configs['flat/recommended'],

  // 2. 关闭和 Prettier 冲突的规则(必须放最后)
  prettierConfig,

  // 3. Vue 文件用 vue-eslint-parser
  {
    files: ['**/*.vue'],
    languageOptions: {
      parser: vueParser,
      parserOptions: {
        parser: tseslint.parser,
        sourceType: 'module',
      },
    },
  },

  // 4. 自定义规则
  {
    rules: {
      // Vue
      'vue/multi-word-component-names': 'off', // 允许 Home.vue / Login.vue
      'vue/attribute-hyphenation': ['error', 'always'], // kebab-case 的 props

      // TS
      '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
      '@typescript-eslint/no-explicit-any': 'warn',

      // 通用
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'no-debugger': 'error',
    },
  },

  // 5. 忽略文件
  {
    ignores: ['dist/**', 'node_modules/**', 'coverage/**', '*.config.js'],
  },
]

理解顺序:数组从上往下应用,后面的会覆盖前面。所以 prettierConfig(关闭格式化规则)必须放共享规则之后


4. Prettier 配置

// .prettierrc.js 或 prettier.config.js
export default {
  semi: false,            // 不加分号(JS 风格两派之一)
  singleQuote: true,      // 单引号
  trailingComma: 'all',   // 尾逗号
  printWidth: 100,        // 每行最多 100 字符
  tabWidth: 2,            // 缩进 2 空格
  arrowParens: 'always',  // 箭头函数参数加括号: (x) => x
  vueIndentScriptAndStyle: false, // <script>/<style> 不缩进一级
  htmlWhitespaceSensitivity: 'ignore',
}

in4vue 用这套。有三个"宗教问题":

4.1 分号

// semi: false
const foo = 'bar'
const baz = 'qux'

// semi: true
const foo = 'bar';
const baz = 'qux';

无分号党(本项目):ES 模块时代不分号更干净,只在极少数"行首是 [ / ("的坑点需要加,Prettier 会自动加。 有分号党:怕"自动插入分号"规则出错。

两派都能活,团队约定一致最重要。

4.2 引号

// singleQuote: true
const name = 'alice'

// singleQuote: false
const name = "alice"

JS 生态单引号占多,本项目用单引号。JSX 属性里 Prettier 默认用双引号(遵循 HTML 习惯),如果想强制单引号:jsxSingleQuote: true

4.3 尾逗号

// trailingComma: 'all'
const config = {
  a: 1,
  b: 2,  // ← 这个逗号
}

推荐 'all':Git diff 友好(新增一行时只加一行,不会同时改上一行加逗号)。


5. ESLint 和 Prettier 怎么不打架

核心问题:ESLint 自带一些代码风格规则indentsemiquotes),Prettier 也管这些,冲突时一边格式化一边报错,死循环。

解法 1eslint-config-prettier

import prettierConfig from 'eslint-config-prettier'

export default [
  // ... 其他规则
  prettierConfig, // 放最后,关掉所有会冲突的 ESLint 规则
]

解法 2eslint-plugin-prettier(可选)

让 ESLint 也去跑 Prettier,格式问题报成 ESLint 错误:

import pluginPrettier from 'eslint-plugin-prettier/recommended'

export default [
  // ... 其他规则
  pluginPrettier, // 会自动包含 eslint-config-prettier
]

优点:只跑 eslint 一条命令就搞定 lint + 格式 缺点:慢一些(ESLint 每处格式差异都要跑 Prettier 格式化再对比)

推荐:分开跑 —— eslint 查错,prettier 格式化。保存时 IDE 两者都调。


6. VS Code 保存时自动格式化

.vscode/settings.json(提交到 Git,团队共享):

{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "eslint.validate": ["javascript", "typescript", "vue"],
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "prettier.requireConfig": true
}

要装的插件

保存 .vue 文件时:

  1. Prettier 先跑格式化
  2. ESLint 再 fix 所有可自动修复的问题
  3. 剩下的 ESLint 错误在编辑器里标红,你手动改

7. Vue 3 常用规则精选

eslint-plugin-vue 有 200+ 规则,只讲最常打开/关闭的几个:

{
  rules: {
    // 组件名
    'vue/multi-word-component-names': 'off', // 默认强制多词(如 UserList),太烦

    // 模板语法
    'vue/html-self-closing': ['error', {
      html: { void: 'always', normal: 'always', component: 'always' },
    }],
    // 效果: <img />  <br />  <MyComp />

    'vue/component-name-in-template-casing': ['error', 'PascalCase'],
    // 效果: <UserCard /> 而不是 <user-card />

    'vue/attributes-order': 'error',
    // 效果: 属性按 v-if → v-for → ref → props → v-on 顺序

    // props / emit
    'vue/define-macros-order': ['error', {
      order: ['defineProps', 'defineEmits', 'defineSlots'],
    }],

    // 禁用弃用 API
    'vue/no-deprecated-v-on-native-modifier': 'error',
    'vue/no-v-html': 'warn', // 用 v-html 提醒 XSS 风险

    // 性能
    'vue/no-use-v-if-with-v-for': 'error',
    // 效果: <li v-for="x in list" v-if="x.show"> 是反模式

    // TypeScript
    '@typescript-eslint/no-unused-vars': ['error', {
      argsIgnorePattern: '^_', // _unused 开头的参数不报错
    }],
    '@typescript-eslint/consistent-type-imports': 'error',
    // 效果: import type { Foo } from './foo' (类型导入更易 tree-shake)
  },
}

7.1 no-console 的取舍

'no-console': ['warn', { allow: ['warn', 'error'] }],

生产构建自动移除:Vite 里加:

// vite.config.ts
export default defineConfig({
  build: {
    // esbuild 内置支持
    minify: 'esbuild',
  },
  esbuild: {
    drop: ['console', 'debugger'],
  },
})

开发时随便 console.log,生产里自动删。


8. 禁用规则的正确姿势

有时候规则确实不该应用,用注释禁用

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = JSON.parse(str)

// 禁用整行
const x: any = foo // eslint-disable-line @typescript-eslint/no-explicit-any

// 禁用整个文件
/* eslint-disable @typescript-eslint/no-explicit-any */

原则

// 第三方库 SDK 返回 any,只能信任
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const sdk: any = window.ThirdPartySDK

9. lint-staged + husky:提交前自动检查

每次 commit 前跑 ESLint/Prettier,保证入库代码干净:

pnpm add -D husky lint-staged
pnpm exec husky init

创建 .husky/pre-commit

pnpm exec lint-staged

package.json 加:

{
  "lint-staged": {
    "*.{ts,vue,js}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,css,md}": [
      "prettier --write"
    ]
  }
}

效果git commit只对本次改动的文件跑 lint,不会检查整个项目。速度快、问题修复直接加到本次 commit。

Java 对照:类似 Maven 的 pre-commit 阶段 —— commit 前执行校验,失败阻止提交。


10. commitlint:规范提交信息

in4vue 的 Git 规范要求:中文 + <类型>: <描述>。用 commitlint 自动校验:

pnpm add -D @commitlint/cli @commitlint/config-conventional

commitlint.config.js

export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'refactor', 'style', 'chore', 'test', 'perf']],
    'subject-case': [0], // 允许中文
  },
}

.husky/commit-msg

pnpm exec commitlint --edit $1

效果

git commit -m "改了个东西"
# ❌ fail: subject may not be empty, type must be one of [...]

git commit -m "feat: 新增笔记搜索功能"
# ✅ pass

11. 全员一致:.editorconfig

不同编辑器默认行为不一,.editorconfig 是跨编辑器的底线统一:

# .editorconfig
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

VS Code、IntelliJ、Vim 都认。即便团队里有人没装 Prettier 插件,缩进至少是一致的。

Java 对照:类似各公司 Java 项目里的 .editorconfig 或 IDEA 的 codeStyles.xml


12. 常见坑点

现象 原因 解法
eslint 报 "parser not found" 没装 @typescript-eslint/parservue-eslint-parser pnpm add -D typescript-eslint vue-eslint-parser
.vue 文件规则不生效 配置里没针对 *.vue 用 vue-eslint-parser files: ['**/*.vue'], languageOptions: { parser: vueParser }
一片红波浪,提示某个规则不认识 插件没装或没在 config 里 use 检查 extends / plugins
Prettier 和 ESLint 互相覆盖 eslint-config-prettier 没放最后 数组最后一项是 prettierConfig
pnpm lint 在 CI 上很慢 跑了整个项目 本地加 lint-staged 只跑改动的
老项目有 .eslintrc.js,ESLint 9 找不到配置 新版默认只找 eslint.config.js 迁移到 flat config 或 ESLINT_USE_FLAT_CONFIG=false 兼容

13. 小决策表

需求 方案
统一代码风格 Prettier
查潜在 bug ESLint
Vue 3 项目 eslint-plugin-vue/flat/recommended
TS 项目 typescript-eslint
两者不打架 eslint-config-prettier 放最后
提交前自动修复 husky + lint-staged
跨编辑器一致 .editorconfig
生产代码不要 console Vite 的 esbuild.drop
规范提交信息 commitlint + husky commit-msg

14. 心智模型

写代码时:       IDE 保存自动格式化 (Prettier) + 实时高亮错误 (ESLint)
git commit 时:  lint-staged 只跑改动文件 + commitlint 检查信息
CI 跑:          eslint . + prettier --check . 全量校验,阻塞合并

三层网下来,代码风格想乱都难。


小练习

  1. 检查 in4vue 的 eslint.config.js,尝试加一条自定义规则(如 no-console: error
  2. 故意写个 var x = 1,看 ESLint 怎么报
  3. 装 husky + lint-staged,提交时自动跑 lint
  4. 装 commitlint,提交一条错格式信息试试是否拦截
  5. 在 VS Code 里改一个 .vue 文件保存,观察是否自动格式化 + 自动修复

延伸阅读