Appearance
ESLint实战案例
本指南通过实际案例展示如何在不同类型的项目中配置和使用ESLint,帮助您理解在实际开发场景中如何应用ESLint。
案例1:React项目配置
项目背景
一个使用React 18和TypeScript的前端项目,需要集成ESLint来保证代码质量。
安装依赖
bash
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y
配置文件
javascript
// .eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
'prettier', // 需要先安装 eslint-config-prettier
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module',
project: './tsconfig.json', // TypeScript项目需要
},
plugins: [
'react',
'@typescript-eslint',
'react-hooks',
'jsx-a11y',
],
settings: {
react: {
version: 'detect', // 自动检测React版本
},
},
rules: {
'react/react-in-jsx-scope': 'off', // React 17+不需要
'react/prop-types': 'off', // 使用TypeScript类型检查
'@typescript-eslint/explicit-module-boundary-types': 'off',
'jsx-a11y/anchor-is-valid': 'off', // Next.js Link组件
},
overrides: [
{
files: ['*.test.*', '*.spec.*'],
env: {
jest: true,
},
rules: {
'no-console': 'off',
},
},
],
};
package.json脚本
json
{
"scripts": {
"lint": "eslint src/ --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint src/ --ext .js,.jsx,.ts,.tsx --fix",
"lint:ci": "eslint src/ --ext .js,.jsx,.ts,.tsx --format=unix --quiet"
}
}
案例2:Node.js后端项目
项目背景
一个Express后端API项目,需要ESLint来保证服务端代码质量。
安装依赖
bash
npm install --save-dev eslint eslint-plugin-node
配置文件
javascript
// .eslintrc.js
module.exports = {
env: {
node: true,
es2021: true,
jest: true, // 包含测试环境
},
extends: [
'eslint:recommended',
'plugin:node/recommended',
],
parserOptions: {
ecmaVersion: 12,
sourceType: 'module',
},
plugins: [
'node',
],
rules: {
'node/no-unpublished-require': 'off', // 允许开发依赖
'node/no-missing-require': 'off', // 允许动态require
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
'no-process-exit': 'off',
'node/handle-callback-err': 'off', // 根据项目情况调整
},
overrides: [
{
files: ['**/*.test.js', '**/*.spec.js'],
env: {
jest: true,
},
rules: {
'node/no-unpublished-require': 'off',
'no-console': 'off',
},
},
{
files: ['scripts/**/*.js'],
rules: {
'no-console': 'off', // 构建脚本可以使用console
},
},
],
};
特殊配置
javascript
// 针对不同环境的配置
module.exports = {
// ... 其他配置
env: {
node: true,
es2021: true,
...(process.env.NODE_ENV === 'test' && { jest: true }),
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
'no-process-exit': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
},
};
案例3:单体仓库(Monorepo)配置
项目背景
一个包含前端React应用、后端Express API和共享工具库的单体仓库。
目录结构
monorepo/
├── .eslintrc.js # 根配置
├── package.json
├── packages/
│ ├── frontend/
│ │ ├── .eslintrc.js # 前端特定配置
│ │ └── src/
│ ├── backend/
│ │ ├── .eslintrc.js # 后端特定配置
│ │ └── src/
│ └── shared/
│ ├── .eslintrc.js # 共享库配置
│ └── src/
└── tools/
└── eslint-config/ # 共享ESLint配置
根配置
javascript
// .eslintrc.js
module.exports = {
root: true, // 根配置,阻止ESLint向上搜索配置
extends: ['eslint:recommended'],
rules: {
'no-console': 'warn',
'no-debugger': 'error',
},
overrides: [
{
files: ['packages/frontend/**/*'],
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'plugin:react/recommended',
],
plugins: ['react'],
settings: {
react: {
version: 'detect',
},
},
},
{
files: ['packages/backend/**/*'],
env: {
node: true,
},
extends: ['eslint:recommended', 'plugin:node/recommended'],
plugins: ['node'],
},
{
files: ['packages/shared/**/*'],
extends: ['eslint:recommended', '@typescript-eslint/recommended'],
plugins: ['@typescript-eslint'],
},
],
};
前端配置
javascript
// packages/frontend/.eslintrc.js
module.exports = {
extends: [
'../../tools/eslint-config/react-base',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'prettier',
],
settings: {
react: {
version: 'detect',
},
},
rules: {
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
},
};
后端配置
javascript
// packages/backend/.eslintrc.js
module.exports = {
extends: [
'../../tools/eslint-config/node-base',
'plugin:node/recommended',
],
env: {
node: true,
es6: true,
},
rules: {
'node/no-unpublished-require': 'off',
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
},
};
案例4:Next.js项目配置
安装依赖
bash
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y @next/eslint-plugin-next
配置文件
javascript
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
'plugin:@next/next/recommended', // Next.js特定规则
'prettier',
],
env: {
browser: true,
node: true,
es6: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module',
},
settings: {
react: {
version: 'detect',
},
},
rules: {
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'@next/next/no-html-link-for-pages': 'off', // 如果页面结构不标准
},
overrides: [
{
files: ['next.config.js'],
env: {
node: true,
},
},
],
};
案例5:Vue.js项目配置
安装依赖
bash
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue @vue/eslint-config-typescript
配置文件
javascript
// .eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential', // 或 vue3-recommended
'@typescript-eslint/recommended',
'prettier',
],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 12,
sourceType: 'module',
},
plugins: [
'vue',
'@typescript-eslint',
],
rules: {
'vue/multi-word-component-names': 'off', // 根据团队偏好调整
'vue/no-unused-vars': 'error',
},
overrides: [
{
files: ['*.vue'],
rules: {
'vue/script-indent': ['error', 2, { baseIndent: 1 }],
},
},
],
};
案例6:CI/CD集成
GitHub Actions工作流
yaml
# .github/workflows/eslint.yml
name: ESLint
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
eslint:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # 获取完整的git历史用于比较
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint on changed files
run: |
# 只检查变更的文件
git diff --name-only HEAD^ HEAD --diff-filter=d | grep -E '\.(js|jsx|ts|tsx|vue)$' | xargs -r npx eslint --max-warnings 0
- name: Run full ESLint
run: npx eslint src/ --ext .js,.jsx,.ts,.tsx --max-warnings 0
生成ESLint报告
bash
# 生成JSON格式报告
npx eslint src/ --ext .js,.jsx,.ts,.tsx --format json --output-file eslint-report.json
# 生成检查报告用于CI
npx eslint src/ --ext .js,.jsx,.ts,.tsx --format unix > eslint-results.txt
案例7:自定义规则开发
创建自定义规则
javascript
// tools/eslint-plugin-custom/rules/no-direct-mutation.js
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Disallow direct mutation of state',
category: 'Best Practices',
recommended: false,
},
fixable: null,
schema: [], // 规则选项
},
create: function(context) {
return {
AssignmentExpression: function(node) {
if (node.left.type === 'MemberExpression' &&
node.left.object.name === 'state') {
context.report({
node: node,
message: 'Direct mutation of state is not allowed',
});
}
},
};
},
};
使用自定义规则
javascript
// .eslintrc.js
module.exports = {
plugins: [
'custom', // 引用自定义插件
],
rules: {
'custom/no-direct-mutation': 'error',
},
};
案例8:性能优化策略
配置性能优化
javascript
// .eslintrc.js
module.exports = {
cache: true,
cacheLocation: 'node_modules/.cache/eslint',
cacheStrategy: 'content',
ignorePatterns: [
'node_modules/',
'dist/',
'build/',
'.next/',
'.nuxt/',
'*.min.js',
'*.bundle.js',
],
// 其他配置...
};
分批处理大项目
json
// package.json
{
"scripts": {
"lint:all": "eslint src/",
"lint:components": "eslint src/components/",
"lint:utils": "eslint src/utils/",
"lint:api": "eslint src/api/",
"lint:parallel": "npm-run-all --parallel lint:* --ignore-scripts"
}
}
案例9:团队协作最佳实践
共享配置包
javascript
// packages/eslint-config-company/index.js
const restrictedImports = require('./restricted-imports');
module.exports = {
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
'no-restricted-imports': ['error', restrictedImports],
'prefer-const': 'error',
'no-var': 'error',
},
env: {
browser: true,
node: true,
es6: true,
},
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
},
};
预提交钩子
json
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --cache --fix",
"git add"
],
"*.{js,jsx,ts,tsx,json,css,md}": [
"prettier --write",
"git add"
]
}
}
这些实战案例展示了如何在不同类型的项目中正确配置和使用ESLint,涵盖了从简单项目到复杂单体仓库的各种场景。