第 132 章:ESLint 与 Prettier
学习目标
- 掌握 ESLint 在 Vue 3 + TypeScript 项目中的配置
- 学会 Prettier 代码格式化与协作
- 理解 ESLint 与 Prettier 的协同
- 在 CI/CD 中集成代码规范检查
一、为什么需要代码规范
二、ESLint 基础
2.1 安装
bash
pnpm add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
pnpm add -D eslint-plugin-vue vue-eslint-parser2.2 初始化
bash
pnpm create @eslint/config2.3 配置文件
javascript
// .eslintrc.cjs
module.exports = {
root: true,
env: {
browser: true,
node: true,
es2022: true
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2022,
sourceType: 'module',
extraFileExtensions: ['.vue']
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier'
],
plugins: ['@typescript-eslint', 'vue'],
rules: {
'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-console': 'warn'
}
};2.4 Flat Config(ESLint 9+)
typescript
// eslint.config.js
import vue from 'eslint-plugin-vue';
import ts from '@typescript-eslint/eslint-plugin';
import vueParser from 'vue-eslint-parser';
import tsParser from '@typescript-eslint/parser';
export default [
{
files: ['**/*.{js,ts,vue}'],
languageOptions: {
parser: vueParser,
parserOptions: {
parser: tsParser,
ecmaVersion: 2022,
sourceType: 'module'
}
},
plugins: { vue, '@typescript-eslint': ts },
rules: {
...vue.configs['vue3-recommended'].rules,
...ts.configs.recommended.rules
}
}
];三、Vue 规则
3.1 常用规则
javascript
rules: {
// 必须有多个单词
'vue/multi-word-component-names': 'error',
// HTML 闭合
'vue/html-self-closing': ['error', {
html: { void: 'always', normal: 'always', component: 'always' }
}],
// 最大属性数
'vue/max-attributes-per-line': ['error', { singleline: 5, multiline: 1 }],
// 名称顺序
'vue/order-in-components': 'error',
// 禁止 v-html
'vue/no-v-html': 'warn',
// prop 类型
'vue/require-default-prop': 'error',
'vue/require-prop-types': 'error',
// v-for 必须有 key
'vue/require-v-for-key': 'error',
// v-if 不要和 v-for 一起用
'vue/no-use-v-if-with-v-for': 'error',
// 不允许单独使用 v-if
'vue/no-v-if-template-key-on-child': 'error'
}3.2 自定义规则
javascript
// 检查组件名
'vue/component-name-in-template-casing': ['error', 'PascalCase', {
registeredComponentsOnly: true,
ignores: []
}]四、TypeScript 规则
4.1 推荐配置
javascript
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking'
]4.2 常用规则
javascript
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/await-thenable': 'error'
}4.3 类型定义
typescript
// 先定义后使用
let value: number = 0;
value = 'hello'; // ❌ 报错五、Prettier
5.1 安装
bash
pnpm add -D prettier5.2 配置
json
// .prettierrc.json
{
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf",
"vueIndentScriptAndStyle": false
}5.3 忽略文件
text
// .prettierignore
node_modules
dist
*.min.js5.4 命令
json
{
"scripts": {
"format": "prettier --write \"src/**/*.{js,ts,vue,json,css,md}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,css,md}\""
}
}六、ESLint + Prettier 协同
6.1 冲突解决
ESLint 处理:代码质量
Prettier 处理:代码格式两者规则可能冲突,需要:
- 关闭 ESLint 中与格式相关的规则
- 启用 eslint-config-prettier
6.2 安装
bash
pnpm add -D eslint-config-prettierjavascript
// .eslintrc.cjs
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier' // 必须在最后
]6.3 验证冲突
bash
# npm
npx eslint-config-prettier .eslintrc.cjs
# pnpm
pnpm dlx eslint-config-prettier .eslintrc.cjs七、Stylelint
7.1 安装
bash
pnpm add -D stylelint stylelint-config-standard stylelint-config-recommended-vue7.2 配置
javascript
// .stylelintrc.cjs
module.exports = {
extends: [
'stylelint-config-standard',
'stylelint-config-recommended-vue'
],
rules: {
'selector-class-pattern': null,
'no-descending-specificity': null
}
};7.3 命令
json
{
"scripts": {
"lint:style": "stylelint \"src/**/*.{css,scss,vue}\""
}
}八、编辑器集成
8.1 VSCode
json
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
]
}8.2 推荐插件
- ESLint
- Prettier
- stylelint
- Volar
- Vue VSCode Snippets
九、Git Hooks
9.1 Husky
bash
pnpm add -D husky
npx husky init9.2 pre-commit
bash
# .husky/pre-commit
pnpm exec lint-staged9.3 lint-staged
bash
pnpm add -D lint-stagedjson
// package.json
{
"lint-staged": {
"*.{js,ts,vue}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss}": [
"stylelint --fix",
"prettier --write"
],
"*.md": [
"prettier --write"
]
}
}9.4 commitlint
bash
pnpm add -D @commitlint/cli @commitlint/config-conventionaljavascript
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional']
};bash
# .husky/commit-msg
pnpm exec commitlint --edit "$1"十、CI 集成
10.1 GitHub Actions
yaml
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm format:check
- run: pnpm type-check10.2 类型检查
json
{
"scripts": {
"type-check": "vue-tsc --noEmit"
}
}十一、组合命令
json
{
"scripts": {
"lint": "eslint \"src/**/*.{js,ts,vue}\" --fix",
"lint:check": "eslint \"src/**/*.{js,ts,vue}\"",
"format": "prettier --write \"src/**/*.{js,ts,vue,json,css,md}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,css,md}\"",
"lint:style": "stylelint \"src/**/*.{css,scss,vue}\" --fix",
"type-check": "vue-tsc --noEmit",
"verify": "pnpm lint:check && pnpm format:check && pnpm lint:style && pnpm type-check"
}
}十二、规则分层
javascript
// .eslintrc.cjs
module.exports = {
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended'
],
overrides: [
{
files: ['*.ts'],
extends: [
'plugin:@typescript-eslint/recommended'
],
rules: {
'@typescript-eslint/explicit-function-return-type': 'off'
}
},
{
files: ['*.test.ts'],
env: {
jest: true
}
},
{
files: ['vite.config.ts'],
env: {
node: true
}
}
]
};十三、常见问题
13.1 ESLint 不识别 .vue
bash
npm install --save-dev eslint-plugin-vue vue-eslint-parserjavascript
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
extraFileExtensions: ['.vue']
}13.2 与 Prettier 冲突
bash
pnpm add -D eslint-config-prettierjavascript
extends: [
// ... 其他
'prettier' // 最后
]13.3 旧代码豁免
javascript
// .eslintrc.cjs
{
ignorePatterns: ['src/legacy/**', '*.min.js']
}javascript
// 单行豁免
// eslint-disable-next-line no-console
console.log('debug');
// 整个文件
/* eslint-disable no-console */十四、lint-staged 进阶
json
{
"lint-staged": {
"*.{js,ts,vue}": [
"eslint --fix --max-warnings=0",
"prettier --write"
],
"*.{css,scss,vue}": [
"stylelint --fix",
"prettier --write"
]
}
}十五、本章小结
| 工具 | 职责 |
|---|---|
| ESLint | 代码质量、错误检查 |
| Prettier | 代码格式化 |
| Stylelint | CSS/SCSS 检查 |
| Husky | Git hooks |
| lint-staged | 仅 lint 暂存文件 |
| commitlint | 提交信息规范 |
动手练习
- 基础配置:为项目配置 ESLint + Prettier
- Vue 规则:为 Vue 3 启用推荐规则集
- Git Hooks:配置 pre-commit 时自动 lint
- CI 集成:在 GitHub Actions 中运行 lint
- 规范提交:配置 commitlint 并使用规范化提交
推荐阅读
- 📖 ESLint 官方文档 — 完整指南
- 📖 eslint-plugin-vue — Vue 规则
- 📖 Prettier 配置 — 配置参考
- 🌐 Conventional Commits — 提交规范
下一章:第 133 章:Vitest 单元测试 →