ESLint + Prettier 配置与规则
1. 后端视角看前端 lint
Java 里你可能用过:
- Checkstyle —— 代码风格(缩进、命名)
- SpotBugs / PMD —— 潜在 bug(空指针、未使用变量)
- Spotless / google-java-format —— 自动格式化
前端对应:
| Java | 前端 |
|---|---|
| Checkstyle + SpotBugs + PMD | ESLint |
| Spotless / google-java-format | Prettier |
| Maven checkstyle plugin | pnpm lint / pnpm format |
@SuppressWarnings |
// eslint-disable-next-line |
一句话总结分工:
- ESLint 管"对不对"(潜在 bug、错误用法)
- Prettier 管"好不好看"(空格、引号、换行)
两个工具各司其职,但规则会部分重叠——这是 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 自带一些代码风格规则(indent、semi、quotes),Prettier 也管这些,冲突时一边格式化一边报错,死循环。
解法 1:eslint-config-prettier
import prettierConfig from 'eslint-config-prettier'
export default [
// ... 其他规则
prettierConfig, // 放最后,关掉所有会冲突的 ESLint 规则
]
解法 2:eslint-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
}
要装的插件:
- ESLint (
dbaeumer.vscode-eslint) - Prettier (
esbenp.prettier-vscode) - Volar (Vue Official) —— Vue 3 的 TS/模板支持
保存 .vue 文件时:
- Prettier 先跑格式化
- ESLint 再
fix所有可自动修复的问题 - 剩下的 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'] }],
- 允许
console.warn/console.error(生产也有价值) console.log警告(提醒清理调试代码)
生产构建自动移除: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 */
原则:
- 必须指定规则名,别写
// eslint-disable-next-line全关 - 禁用前先问:是规则错了还是代码错了?大多数时候是代码该改
- 禁用时加注释解释:
// 第三方库 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/parser 或 vue-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 . 全量校验,阻塞合并
三层网下来,代码风格想乱都难。
小练习
- 检查 in4vue 的
eslint.config.js,尝试加一条自定义规则(如no-console: error) - 故意写个
var x = 1,看 ESLint 怎么报 - 装 husky + lint-staged,提交时自动跑 lint
- 装 commitlint,提交一条错格式信息试试是否拦截
- 在 VS Code 里改一个
.vue文件保存,观察是否自动格式化 + 自动修复