
引言
作为前端开发者,你是否遇到过这样的情况:团队成员写出的代码风格各异,有人喜欢用分号,有人不用;有人用双引号,有人用单引号;代码评审时总是在纠结这些格式问题而不是业务逻辑?或者在大型项目中,因为一个未定义的变量导致生产环境报错?
ESLint 就是为了解决这些问题而生的。它不仅能统一代码风格,更重要的是能在开发阶段就发现潜在的错误,提高代码质量和开发效率。
本文将从零开始,带你全面掌握 ESLint 的使用,从基础配置到高级定制,从个人项目到团队协作,让你成为 ESLint 的专家。
什么是ESLint?
定义与作用
ESLint 是一个开源的 JavaScript 代码静态分析工具,由 Nicholas C. Zakas 在 2013 年创建。它的主要作用是:
- 代码质量检查:识别有问题的模式或不符合特定规则的代码
- 代码风格统一:强制执行一致的代码风格
- 错误预防:在运行前捕获潜在的错误
- 最佳实践提醒:推广 JavaScript 最佳实践
核心特性
- 完全可配置:所有规则都可以开启/关闭,每个规则都有多个设置选项
- 插件化架构:可以通过插件扩展功能,支持 TypeScript、React、Vue 等
- 支持多种配置格式:JSON、YAML、JavaScript 等
- IDE 集成:主流编辑器都有相应插件
- 自动修复:大部分格式问题可以自动修复
安装与基础配置
安装ESLint
bash
# 全局安装(不推荐)
npm install -g eslint
# 项目内安装(推荐)
npm install --save-dev eslint
# 使用 yarn
yarn add --dev eslint
# 使用 pnpm
pnpm add -D eslint
初始化配置
bash
# 交互式创建配置文件
npx eslint --init
# 或者使用
npm init @eslint/config
执行命令后,ESLint 会问你几个问题:
-
How would you like to use ESLint?
- To check syntax only(仅检查语法)
- To check syntax and find problems(检查语法并发现问题)
- To check syntax, find problems, and enforce code style(检查语法、发现问题并强制代码风格)
-
What type of modules does your project use?
- JavaScript modules (import/export)
- CommonJS (require/exports)
- None of these
-
Which framework does your project use?
- React
- Vue.js
- None of these
-
Does your project use TypeScript? Yes/No
-
Where does your code run?
- Browser
- Node
-
What format do you want your config file to be in?
- JavaScript
- YAML
- JSON
基础配置文件示例
根据你的选择,ESLint 会生成对应的配置文件。以 .eslintrc.js
为例:
javascript
module.exports = {
// 环境定义
env: {
browser: true,
es2021: true,
node: true
},
// 继承的配置
extends: [
'eslint:recommended'
],
// 解析器选项
parserOptions: {
ecmaVersion: 12,
sourceType: 'module'
},
// 自定义规则
rules: {
// 在这里添加或覆盖规则
}
};
配置文件详解
配置文件类型与优先级
ESLint 支持多种配置文件格式,优先级从高到低:
.eslintrc.js
.eslintrc.cjs
.eslintrc.yaml
或.eslintrc.yml
.eslintrc.json
package.json
中的eslintConfig
字段
核心配置选项
1. env(环境配置)
定义代码运行的环境,影响全局变量的可用性:
javascript
module.exports = {
env: {
browser: true, // 浏览器全局变量
node: true, // Node.js 全局变量
es2021: true, // ES2021 语法支持
jest: true, // Jest 测试环境
jquery: true, // jQuery 全局变量
worker: true, // Web Worker
serviceworker: true // Service Worker
}
};
2. extends(扩展配置)
继承其他的配置文件或预设规则集:
javascript
module.exports = {
extends: [
'eslint:recommended', // ESLint 推荐规则
'@typescript-eslint/recommended', // TypeScript 推荐规则
'plugin:react/recommended', // React 推荐规则
'plugin:vue/essential', // Vue 基础规则
'airbnb', // Airbnb 风格指南
'prettier' // Prettier 兼容
]
};
3. parser(解析器)
指定 ESLint 使用的解析器:
javascript
module.exports = {
// TypeScript 解析器
parser: '@typescript-eslint/parser',
// Babel 解析器
// parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
ecmaFeatures: {
jsx: true, // 支持 JSX
globalReturn: true, // 允许全局 return
impliedStrict: true // 启用严格模式
}
}
};
4. plugins(插件)
扩展 ESLint 功能的插件:
javascript
module.exports = {
plugins: [
'@typescript-eslint', // TypeScript 插件
'react', // React 插件
'react-hooks', // React Hooks 插件
'import', // import/export 插件
'jsx-a11y', // 无障碍访问插件
'prettier' // Prettier 插件
]
};
5. rules(规则配置)
这是 ESLint 的核心,定义具体的检查规则:
javascript
module.exports = {
rules: {
// 错误级别: "off" 或 0, "warn" 或 1, "error" 或 2
// 代码质量相关
'no-unused-vars': 'error', // 禁止未使用的变量
'no-undef': 'error', // 禁止使用未定义的变量
'no-console': 'warn', // 警告使用 console
'no-debugger': 'error', // 禁止使用 debugger
// 代码风格相关
'indent': ['error', 2], // 强制缩进为 2 个空格
'quotes': ['error', 'single'], // 强制使用单引号
'semi': ['error', 'always'], // 强制使用分号
'comma-dangle': ['error', 'never'], // 禁止末尾逗号
// ES6+ 相关
'prefer-const': 'error', // 优先使用 const
'arrow-spacing': 'error', // 箭头函数空格
'template-curly-spacing': 'error', // 模板字符串空格
// 函数相关
'func-style': ['error', 'declaration'], // 函数声明风格
'max-params': ['error', 4], // 最多 4 个参数
// 对象和数组
'object-curly-spacing': ['error', 'always'], // 对象花括号空格
'array-bracket-spacing': ['error', 'never'], // 数组方括号空格
}
};
高级配置选项
1. globals(全局变量)
定义额外的全局变量:
javascript
module.exports = {
globals: {
myCustomGlobal: 'readonly', // 只读
anotherGlobal: 'writable', // 可写
$: 'readonly', // jQuery
_: 'readonly' // Lodash
}
};
2. overrides(覆盖配置)
为特定文件或目录设置不同的规则:
javascript
module.exports = {
rules: {
// 全局规则
'no-console': 'error'
},
overrides: [
{
// 对测试文件的特殊配置
files: ['**/*.test.js', '**/*.spec.js'],
env: {
jest: true
},
rules: {
'no-console': 'off' // 测试文件允许使用 console
}
},
{
// 对 TypeScript 文件的配置
files: ['**/*.ts', '**/*.tsx'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/no-unused-vars': 'error'
}
}
]
};
3. ignorePatterns(忽略模式)
指定要忽略的文件和目录:
javascript
module.exports = {
ignorePatterns: [
'dist/',
'build/',
'node_modules/',
'*.min.js',
'coverage/'
]
};
常用规则详解
代码质量规则
1. 变量相关
javascript
{
// 禁止使用未声明的变量
'no-undef': 'error',
// 禁止未使用的变量
'no-unused-vars': ['error', {
vars: 'all', // 检查所有变量
args: 'after-used', // 检查使用后的参数
ignoreRestSiblings: true // 忽略剩余兄弟元素
}],
// 禁止重复声明变量
'no-redeclare': 'error',
// 禁止在变量定义之前使用
'no-use-before-define': ['error', {
functions: false, // 函数声明提升
classes: true,
variables: true
}]
}
2. 函数相关
javascript
{
// 要求或禁止使用命名的 function 表达式
'func-names': ['error', 'as-needed'],
// 强制函数最大行数
'max-lines-per-function': ['error', {
max: 50,
skipBlankLines: true,
skipComments: true
}],
// 限制函数参数数量
'max-params': ['error', 4],
// 禁止使用 arguments.caller 或 arguments.callee
'no-caller': 'error'
}
3. 对象和数组
javascript
{
// 禁止对象字面量中出现重复的 key
'no-dupe-keys': 'error',
// 禁止数组中出现重复的元素
'no-dupe-args': 'error',
// 强制对象字面量属性名称使用一致的引号
'quote-props': ['error', 'as-needed'],
// 要求对象字面量简写语法
'object-shorthand': ['error', 'always']
}
代码风格规则
1. 空格和缩进
javascript
{
// 强制使用一致的缩进
'indent': ['error', 2, {
SwitchCase: 1, // switch 语句缩进
VariableDeclarator: 1, // 变量声明缩进
outerIIFEBody: 1 // IIFE 缩进
}],
// 强制在逗号前后使用一致的空格
'comma-spacing': ['error', {
before: false,
after: true
}],
// 强制在对象字面量的属性中键和值之间使用一致的间距
'key-spacing': ['error', {
beforeColon: false,
afterColon: true
}]
}
2. 引号和分号
javascript
{
// 强制使用一致的引号
'quotes': ['error', 'single', {
avoidEscape: true, // 避免转义
allowTemplateLiterals: true // 允许模板字符串
}],
// 要求或禁止使用分号
'semi': ['error', 'always'],
// 强制分号之前和之后使用一致的空格
'semi-spacing': ['error', {
before: false,
after: true
}]
}
ES6+ 规则
javascript
{
// 要求使用 const 声明那些声明后不再被修改的变量
'prefer-const': 'error',
// 要求使用箭头函数作为回调
'prefer-arrow-callback': 'error',
// 要求使用模板字面量而非字符串连接
'prefer-template': 'error',
// 强制箭头函数的箭头前后使用一致的空格
'arrow-spacing': ['error', {
before: true,
after: true
}],
// 要求解构赋值
'prefer-destructuring': ['error', {
array: true,
object: true
}]
}
实际项目配置示例
React项目配置
javascript
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended'
],
parser: '@babel/eslint-parser',
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 12,
sourceType: 'module',
requireConfigFile: false,
babelOptions: {
presets: ['@babel/preset-react']
}
},
plugins: [
'react',
'react-hooks',
'jsx-a11y'
],
rules: {
// React 相关
'react/prop-types': 'error',
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
// React Hooks
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
// JSX 相关
'jsx-quotes': ['error', 'prefer-double'],
'react/jsx-indent': ['error', 2],
'react/jsx-indent-props': ['error', 2]
},
settings: {
react: {
version: 'detect'
}
}
};
TypeScript项目配置
javascript
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'@typescript-eslint/recommended',
'@typescript-eslint/recommended-requiring-type-checking'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 12,
sourceType: 'module',
project: './tsconfig.json'
},
plugins: [
'@typescript-eslint'
],
rules: {
// TypeScript 特定规则
'@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-non-null-assertion': 'warn',
// 类型检查
'@typescript-eslint/strict-boolean-expressions': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/prefer-optional-chain': 'error',
// 命名约定
'@typescript-eslint/naming-convention': [
'error',
{
selector: 'interface',
format: ['PascalCase'],
prefix: ['I']
},
{
selector: 'typeAlias',
format: ['PascalCase']
},
{
selector: 'enum',
format: ['PascalCase']
}
]
}
};
Node.js项目配置
javascript
module.exports = {
env: {
node: true,
es2021: true
},
extends: [
'eslint:recommended'
],
parserOptions: {
ecmaVersion: 12,
sourceType: 'module'
},
rules: {
// Node.js 特定规则
'no-process-exit': 'error',
'no-process-env': 'off',
'global-require': 'error',
// 回调函数
'callback-return': 'error',
'handle-callback-err': 'error',
// Buffer 相关
'no-buffer-constructor': 'error',
// 路径相关
'no-path-concat': 'error',
// 同步方法
'no-sync': 'warn'
}
};
命令行使用
基本命令
bash
# 检查单个文件
npx eslint file.js
# 检查多个文件
npx eslint file1.js file2.js
# 检查目录
npx eslint src/
# 检查特定扩展名的文件
npx eslint src/ --ext .js,.jsx,.ts,.tsx
# 自动修复可修复的问题
npx eslint src/ --fix
# 输出格式化
npx eslint src/ --format table
npx eslint src/ --format json
高级命令选项
bash
# 忽略 .eslintignore 文件
npx eslint src/ --no-ignore
# 指定配置文件
npx eslint src/ --config .eslintrc.custom.js
# 只运行特定规则
npx eslint src/ --rule 'quotes: error'
# 禁用特定规则
npx eslint src/ --rule 'no-console: off'
# 缓存结果以提高性能
npx eslint src/ --cache
# 指定缓存位置
npx eslint src/ --cache --cache-location .eslintcache
# 最大警告数
npx eslint src/ --max-warnings 0
package.json 脚本配置
json
{
"scripts": {
"lint": "eslint src/",
"lint:fix": "eslint src/ --fix",
"lint:check": "eslint src/ --max-warnings 0",
"lint:cache": "eslint src/ --cache",
"precommit": "lint-staged"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"git add"
]
}
}
IDE集成
VS Code集成
-
安装ESLint插件
- 在扩展商店搜索 "ESLint"
- 安装官方的 ESLint 插件
-
配置settings.json
json
{
"eslint.enable": true,
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.workingDirectories": ["./src"]
}
WebStorm/IDEA集成
- 打开 Settings/Preferences
- 导航到 Languages & Frameworks > JavaScript > Code Quality Tools > ESLint
- 勾选 "Automatic ESLint configuration"
- 配置 "Run eslint --fix on save"
与其他工具集成
与Prettier集成
bash
# 安装相关包
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
# .eslintrc.js 配置
module.exports = {
extends: [
'eslint:recommended',
'prettier' // 必须放在最后
],
plugins: ['prettier'],
rules: {
'prettier/prettier': 'error'
}
};
# .prettierrc 配置
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2
}
与Husky和lint-staged集成
bash
# 安装
npm install --save-dev husky lint-staged
# package.json 配置
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write",
"git add"
]
}
}
与Webpack集成
javascript
// webpack.config.js
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
plugins: [
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
fix: true,
cache: true
})
]
};
自定义规则开发
创建简单的自定义规则
javascript
// rules/no-console-log.js
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow console.log statements',
category: 'Best Practices',
recommended: false
},
fixable: 'code',
schema: []
},
create(context) {
return {
CallExpression(node) {
if (
node.callee.type === 'MemberExpression' &&
node.callee.object.name === 'console' &&
node.callee.property.name === 'log'
) {
context.report({
node,
message: 'console.log is not allowed',
fix(fixer) {
return fixer.remove(node.parent);
}
});
}
}
};
}
};
使用自定义规则
javascript
// .eslintrc.js
module.exports = {
rules: {
'local/no-console-log': 'error'
},
plugins: ['local']
};
// eslint-plugin-local/index.js
module.exports = {
rules: {
'no-console-log': require('./rules/no-console-log')
}
};
性能优化
缓存配置
bash
# 启用缓存
npx eslint src/ --cache
# 指定缓存文件位置
npx eslint src/ --cache --cache-location node_modules/.cache/eslint
并行处理
json
{
"scripts": {
"lint:parallel": "eslint src/ --cache --fix --max-warnings 0"
}
}
忽略文件配置
bash
# .eslintignore
node_modules/
dist/
build/
coverage/
*.min.js
*.bundle.js
public/
团队协作最佳实践
1. 统一配置管理
javascript
// eslint-config-company/index.js
module.exports = {
extends: [
'eslint:recommended',
'@typescript-eslint/recommended'
],
rules: {
// 公司统一规则
'indent': ['error', 2],
'quotes': ['error', 'single'],
'semi': ['error', 'always']
}
};
// 项目中使用
// .eslintrc.js
module.exports = {
extends: ['@company/eslint-config']
};
2. 渐进式引入
javascript
// 第一阶段:只启用错误级别规则
module.exports = {
extends: ['eslint:recommended'],
rules: {
// 只修复明显错误
'no-unused-vars': 'error',
'no-undef': 'error'
}
};
// 第二阶段:添加警告级别规则
module.exports = {
extends: ['eslint:recommended'],
rules: {
'no-unused-vars': 'error',
'no-undef': 'error',
'no-console': 'warn', // 新增警告
'prefer-const': 'warn'
}
};
// 第三阶段:提升为错误级别
module.exports = {
extends: ['eslint:recommended'],
rules: {
'no-unused-vars': 'error',
'no-undef': 'error',
'no-console': 'error', // 提升为错误
'prefer-const': 'error'
}
};
3. CI/CD 集成
yaml
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- run: npm ci
- run: npm run lint:check
常见问题与解决方案
1. 解析错误
问题 :Parsing error: Unexpected token
解决:检查解析器配置,确保支持使用的语法特性
javascript
module.exports = {
parser: '@babel/eslint-parser',
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
requireConfigFile: false
}
};
2. 规则冲突
问题 :ESLint 和 Prettier 规则冲突
解决:使用 eslint-config-prettier
javascript
module.exports = {
extends: [
'eslint:recommended',
'prettier' // 必须放在最后,覆盖冲突规则
]
};
3. 性能问题
问题 :ESLint 运行很慢
解决:
- 启用缓存:
--cache
- 使用 .eslintignore 忽略不必要的文件
- 考虑使用 eslint_d
bash
# 安装 eslint_d(ESLint 守护进程)
npm install -g eslint_d
# 使用 eslint_d 替代 eslint
eslint_d src/
4. 内存溢出
问题 :JavaScript heap out of memory
解决:增加 Node.js 内存限制
json
{
"scripts": {
"lint": "node --max-old-space-size=4096 node_modules/.bin/eslint src/"
}
}