作为一个经历过无数次代码审查痛苦的前端开发者,我深刻体会到统一代码风格的重要性。记得去年接手一个遗留项目时,发现同一个文件里居然混杂着四种不同的缩进风格、三种引号用法,还有各种随心所欲的换行。这种代码不仅难以维护,更让团队协作变成了一场噩梦。
ESLint 和 Prettier 的组合就像是给项目请了两位专业管家:一位负责检查代码质量(ESLint),另一位负责保持代码美观(Prettier)。特别是在 Vue 3 + TypeScript + Vite 这种现代技术栈中,它们的价值更加凸显。
提示:虽然本文以 Vue 3 项目为例,但配置思路同样适用于 React、Angular 等其他框架,只需调整对应的插件即可。
首先确保你已经初始化了一个 Vite + Vue 3 + TypeScript 项目。如果还没有,可以运行:
bash复制npm create vite@latest my-project --template vue-ts
现代前端项目建议使用 ESLint 的扁平化配置(Flat Config),这是 ESLint 未来的发展方向。安装以下核心依赖:
bash复制npm install -D eslint @eslint/js
接着安装 Vue 和 TypeScript 支持插件:
bash复制npm install -D eslint-plugin-vue @vue/eslint-config-typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
为了让 ESLint 和 Prettier 和谐共处,需要安装集成插件:
bash复制npm install -D eslint-config-prettier eslint-plugin-prettier prettier
这里有个常见误区:很多人会同时安装 eslint-plugin-prettier 和 prettier-eslint,其实只需要前者就够了。后者是另一种集成方式,容易造成混淆。
在项目根目录创建 eslint.config.js(注意不是传统的 .eslintrc.js):
javascript复制import js from '@eslint/js';
import prettierConfig from 'eslint-config-prettier';
import prettierPlugin from 'eslint-plugin-prettier';
import globals from 'globals';
import vue from 'eslint-plugin-vue';
import vueTsConfig from '@vue/eslint-config-typescript';
import tseslint from '@typescript-eslint/eslint-plugin';
export default [
// 排除不需要检查的文件
{
ignores: ['node_modules/', 'dist/', 'vite.config.*', '.prettierrc.cjs', 'prettier.config.cjs'],
},
// 基础 JS 规则
js.configs.recommended,
// 禁用与 Prettier 冲突的 ESLint 规则(必须放在 vue/ts 规则前)
prettierConfig,
// Vue 3 核心规则
...vue.configs['flat/essential'],
...vue.configs['flat/strongly-recommended'],
...vue.configs['flat/recommended'],
// Vue + TS 整合规则
...vueTsConfig(),
{
files: ['**/*.{js,jsx,ts,tsx,vue}'],
languageOptions: {
globals: {
...globals.browser,
...globals.node,
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
},
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: {
prettier: prettierPlugin,
'@typescript-eslint': tseslint,
},
rules: {
'prettier/prettier': 'error',
// Vue 专属规则
'vue/multi-word-component-names': 'off',
'vue/no-unused-vars': 'error',
'vue/no-v-html': 'warn',
// TS 专属规则
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/ban-ts-comment': 'warn',
// 通用规则
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-undef': 'off',
},
},
];
规则优先级:eslint-config-prettier 必须放在 Vue 和 TS 规则之前,这样才能正确禁用冲突的格式规则。
Vue 宏函数处理:Vue 3 的 defineProps 等宏函数需要声明为全局变量,否则 ESLint 会报未定义错误。
环境区分:生产环境禁用 console 和 debugger,开发环境则相对宽松。
渐进式采用:像 no-explicit-any 这样的严格规则先设为警告,给团队适应时间。
在项目根目录创建 prettier.config.cjs:
javascript复制module.exports = {
printWidth: 120,
tabWidth: 2,
useTabs: false,
singleQuote: true,
semi: true,
trailingComma: 'es5',
bracketSpacing: true,
arrowParens: 'avoid',
endOfLine: 'lf',
vueIndentScriptAndStyle: true,
singleAttributePerLine: false
};
printWidth:Vue 单文件组件建议设为 100-120,比纯 JS 项目稍大。
vueIndentScriptAndStyle:确保 <script> 和 <style> 内的代码也能正确缩进。
singleAttributePerLine:Vue 3 的长属性建议保持单行,提高可读性。
添加 .prettierignore:
code复制node_modules/
dist/
.eslint.config.js
.prettierrc.js
vite.config.ts
*.md
*.json
public/
在项目 .vscode/settings.json 中添加:
json复制{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"typescript.tsdk": "node_modules/typescript/lib"
}
在 package.json 中添加:
json复制{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write \"**/*.{vue,js,ts,jsx,tsx,css,less,md}\""
}
}
配置文件格式问题:
.cjs 后缀require 错误,检查文件扩展名和 package.json 的 type 字段规则冲突:
eslint-config-prettier 放在其他配置之前npx eslint-config-prettier-checkVue 文件格式化问题:
prettier-plugin-vuevueIndentScriptAndStyle 配置增量检查:只检查变动的文件
bash复制eslint --cache --fix
限制检查范围:配合 git diff 只检查修改的文件
bash复制eslint $(git diff --name-only HEAD | grep '\.vue$')
禁用不必要的规则:大型项目可以暂时关闭耗时的规则如 import/no-cycle
安装 husky 和 lint-staged:
bash复制npm install -D husky lint-staged
在 package.json 中添加:
json复制{
"lint-staged": {
"*.{js,ts,vue}": ["eslint --fix", "prettier --write"]
}
}
设置 pre-commit 钩子:
bash复制npx husky add .husky/pre-commit "npx lint-staged"
在 eslint.config.js 中,后面的规则会覆盖前面的。利用这个特性可以实现:
javascript复制{
rules: {
// 项目通用规则
'@typescript-eslint/no-explicit-any': 'warn'
}
},
{
files: ['src/utils/*.ts'],
rules: {
// 工具函数更严格
'@typescript-eslint/no-explicit-any': 'error'
}
}
根据环境变量调整规则严格程度:
javascript复制const isStrictMode = process.env.LINT_STRICT === 'true';
rules: {
'@typescript-eslint/no-explicit-any': isStrictMode ? 'error' : 'warn'
}
大型项目可以提取公共配置:
javascript复制// eslint-config-shared.js
export const baseConfig = {
rules: {
// 公共规则
}
};
// 项目中的 eslint.config.js
import { baseConfig } from 'eslint-config-shared';
export default [...baseConfig];
成功配置后,运行 npm run lint 应该看到类似输出:
code复制/src/components/HelloWorld.vue
15:5 warning Unexpected console statement no-console
22:3 error Missing return type on function @typescript-eslint/explicit-function-return-type
✖ 2 problems (1 error, 1 warning)
在 GitHub Actions 中添加 lint 检查:
yaml复制name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run lint
使用 ESLint 的 --format 选项生成报告:
bash复制eslint . --format json --output-file eslint-report.json
然后可以用工具分析错误趋势,逐步提高代码质量。
至少每季度更新一次 ESLint 和 Prettier 相关依赖:
bash复制npm outdated
npm update eslint @eslint/js eslint-plugin-vue @typescript-eslint/eslint-plugin prettier
--fix 自动修复可修复的问题为每个自定义规则添加注释说明:
javascript复制rules: {
// 允许单单词组件名,因为我们的业务组件有大量简单展示组件
'vue/multi-word-component-names': 'off'
}
虽然 ESLint + Prettier 是主流选择,但了解其他方案也很重要:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| StandardJS | 零配置 | 无法定制规则 | 小型项目/快速原型 |
| Biome | 性能极佳 | 生态不成熟 | 超大型项目 |
| Rome | 一体化工具 | 不稳定 | 实验性项目 |
eslint.config.js 的 files 模式匹配范围内ESLint: Output 面板npx eslint your-file.vue.prettierignore 中npx prettier --write your-file.vueeditor.defaultFormatter 设置如果 lint 速度慢:
--cache 选项import/no-cycleeslint-plugin-prettier 的 prettier --check 替代方案以下是一个大型后台管理系统实际使用的配置:
javascript复制// eslint.config.js
import js from '@eslint/js';
import prettierConfig from 'eslint-config-prettier';
import globals from 'globals';
import vue from 'eslint-plugin-vue';
import tseslint from '@typescript-eslint/eslint-plugin';
const isCI = process.env.CI === 'true';
export default [
{
ignores: ['**/dist/**', '**/coverage/**', '**/cypress/**'],
},
js.configs.recommended,
prettierConfig,
...vue.configs['flat/recommended'],
{
files: ['**/*.ts', '**/*.vue'],
plugins: {
'@typescript-eslint': tseslint,
},
languageOptions: {
parserOptions: {
project: './tsconfig.json',
},
},
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-floating-promises': isCI ? 'error' : 'warn',
},
},
{
files: ['**/src/utils/**'],
rules: {
'@typescript-eslint/no-explicit-any': 'error',
},
},
];
随着前端工具链的发展,ESLint 和 Prettier 也在不断进化:
不过目前来看,ESLint + Prettier 的组合在未来几年仍会是主流选择。