什么是 ESLint#
ESLint 是一个开源的 JavaScript 代码检查工具,用于识别和报告代码中的模式问题,帮助开发者:
- 🔍 发现问题:找出潜在的错误和 bug
- 📏 统一风格:强制执行一致的代码风格
- ⚡ 自动修复:自动修复可修复的问题
- 🔧 高度可配置:支持自定义规则和插件
- 🚀 现代化:支持 ES6+、TypeScript、JSX 等
# 安装 ESLint
npm install --save-dev eslint
# 初始化配置文件(ESLint 8.x)
npx eslint --init本文档基于 ESLint 8.x 编写,该版本已于 2024-10-05 停止维护。建议新项目使用 ESLint 9.x 及其扁平化配置(Flat Config)。
ESLint 8.x vs 9.x 主要区别:
- ✅ ESLint 9.x(推荐新项目):
- 使用
eslint.config.js扁平化配置格式 - 移除
env选项,使用globals包代替 - 配置格式更简洁,采用数组形式
ecmaVersion默认为"latest",sourceType默认为"module"- ⚠️ ESLint 8.x(本文档):
- 使用
.eslintrc.js/.eslintrc.json配置格式 - 支持
env、extends等传统配置选项 - 仍然广泛使用于现有项目中
ESLint 10.x 重大变更:
- ❌ 完全移除对旧配置格式(
.eslintrc.*)的支持 - ❌ 移除
ESLINT_USE_FLAT_CONFIG环境变量 - ✅ 只支持扁平化配置格式(
eslint.config.js)
- 本文档适用于使用 ESLint 8.x 及传统配置格式的项目
- 如果你正在启动新项目,建议直接使用 ESLint 9.x+ 和扁平化配置
- 现有项目可以使用
@eslint/migrate-config工具迁移到新格式 - 配置迁移指南:https://eslint.org/docs/latest/use/configure/migration-guide
配置文件#
ESLint 8.x 支持多种配置文件格式:
# JavaScript 格式(推荐)
.eslintrc.js
.eslintrc.cjs
# JSON 格式
.eslintrc.json
.eslintrc
# YAML 格式
.eslintrc.yaml
.eslintrc.yml
# package.json 中配置
{
"eslintConfig": {
// 配置项
}
}推荐使用 .eslintrc.js 或 .eslintrc.cjs,本文以 JavaScript 格式为例。
配置文件后缀说明#
.eslintrc.js vs .eslintrc.cjs#
根据项目的模块系统选择:
1. .eslintrc.js
// .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
browser: true,
},
rules: {
"no-console": "warn",
},
};使用模块系统:
package.json中"type": "commonjs"或未指定 → CommonJSpackage.json中"type": "module"→ ES Module(需要export default)
2. .eslintrc.cjs(ES Module 项目推荐)
// .eslintrc.cjs
module.exports = {
root: true,
env: {
node: true,
browser: true,
},
};适用场景:
- 项目
package.json中有"type": "module" - 明确使用 CommonJS 语法
- 避免模块系统混淆
一、核心配置选项#
1.1 root#
作用:限制 ESLint 向上查找配置文件。
{
"root": true
}默认值:false
影响对比:
// root: false(默认)
// ESLint 会向上查找父目录的配置文件,直到找到 root: true 或到达文件系统根目录
project/
├── .eslintrc.js (root: false)
├── src/
│ └── index.js
└── parent/
└── .eslintrc.js // 也会被应用
// root: true
// ESLint 只使用当前项目的配置,不再向上查找
project/
├── .eslintrc.js (root: true) // 只使用这个
├── src/
│ └── index.js使用建议:
- 项目根目录:
true(推荐) - 子目录覆盖配置:
false
1.2 env#
作用:指定代码运行环境,自动添加对应的全局变量。
{
"env": {
"browser": true, // 浏览器全局变量
"node": true, // Node.js 全局变量
"es2021": true // ES2021 全局变量
}
}常用环境:
{
"env": {
// 运行环境
"browser": true, // 浏览器全局变量(window, document, localStorage 等)
"node": true, // Node.js 全局变量(process, __dirname, require 等)
"worker": true, // Web Worker 全局变量
"serviceworker": true,// Service Worker 全局变量
"commonjs": true, // CommonJS 全局变量(module, exports)
"shared-node-browser": true, // Node.js 和浏览器共享的全局变量
"amd": true, // AMD 规范的 require() 和 define()
// ECMAScript 版本(同时设置 parserOptions.ecmaVersion)
"es6": true, // ES6 全局变量(Promise, Set, Map),ecmaVersion 设为 6
"es2016": true, // ES2016 全局变量,ecmaVersion 设为 7
"es2017": true, // ES2017 全局变量,ecmaVersion 设为 8
"es2018": true, // ES2018 全局变量,ecmaVersion 设为 9
"es2019": true, // ES2019 全局变量,ecmaVersion 设为 10
"es2020": true, // ES2020 全局变量(BigInt, globalThis),ecmaVersion 设为 11
"es2021": true, // ES2021 全局变量,ecmaVersion 设为 12
"es2022": true, // ES2022 全局变量,ecmaVersion 设为 13
"es2023": true, // ES2023 全局变量,ecmaVersion 设为 14
"es2024": true, // ES2024 全局变量,ecmaVersion 设为 15
// 测试框架
"jest": true, // Jest 全局变量(describe, test, expect)
"mocha": true, // Mocha 全局变量(describe, it, before)
"jasmine": true, // Jasmine 全局变量
"qunit": true, // QUnit 全局变量
// 其他
"jquery": true, // jQuery 全局变量($, jQuery)
"mongo": true, // MongoDB 全局变量
"greasemonkey": true, // GreaseMonkey 全局变量
"webextensions": true // WebExtensions 全局变量
}
}影响对比:
// ❌ 未配置 env.browser
console.log(window.location); // ❌ 错误:'window' is not defined
document.querySelector(".btn"); // ❌ 错误:'document' is not defined
// ✅ 配置 env.browser: true
console.log(window.location); // ✅ 正确
document.querySelector(".btn"); // ✅ 正确
// ❌ 未配置 env.node
console.log(process.env.NODE_ENV); // ❌ 错误:'process' is not defined
const path = require("path"); // ❌ 错误:'require' is not defined
// ✅ 配置 env.node: true
console.log(process.env.NODE_ENV); // ✅ 正确
const path = require("path"); // ✅ 正确
1.3 globals#
作用:定义自定义全局变量。
{
"globals": {
"$": "readonly", // jQuery(只读)
"myGlobal": "writable", // 可写全局变量
"MY_CONST": "readonly" // 只读常量
}
}可选值:
"readonly":只读,不可修改"writable":可读写"off":禁用该全局变量(即使环境中定义了也不可用)
影响对比:
// ❌ 未声明全局变量
console.log(myAPI); // ❌ 错误:'myAPI' is not defined
// ✅ 配置 globals
{
"globals": {
"myAPI": "readonly"
}
}
console.log(myAPI); // ✅ 正确
// readonly vs writable
{
"globals": {
"config": "readonly"
}
}
config = {}; // ❌ 错误:'config' is read-only
{
"globals": {
"config": "writable"
}
}
config = {}; // ✅ 正确
1.4 extends#
作用:继承共享配置。
{
"extends": [
"eslint:recommended", // ESLint 推荐规则
"plugin:vue/vue3-recommended", // Vue 3 推荐规则
"plugin:@typescript-eslint/recommended" // TypeScript 推荐规则
]
}常用配置:
{
"extends": [
// ESLint 官方
"eslint:recommended", // 核心推荐规则
"eslint:all", // 所有规则(不推荐)
// Vue
"plugin:vue/vue3-essential", // Vue 3 必要规则
"plugin:vue/vue3-strongly-recommended", // Vue 3 强烈推荐
"plugin:vue/vue3-recommended", // Vue 3 推荐规则(最严格)
// React
"plugin:react/recommended", // React 推荐规则
"plugin:react-hooks/recommended", // React Hooks 规则
// TypeScript
"plugin:@typescript-eslint/recommended", // TS 推荐规则
"plugin:@typescript-eslint/recommended-requiring-type-checking", // 需要类型检查
// Prettier(必须放在最后)
"plugin:prettier/recommended"
]
}配置顺序:后面的配置会覆盖前面的。
{
"extends": [
"eslint:recommended", // 基础规则
"plugin:vue/vue3-recommended", // Vue 规则(可能覆盖基础规则)
"plugin:prettier/recommended" // Prettier 规则(必须最后,禁用冲突规则)
]
}1.5 plugins#
作用:加载第三方插件。
{
"plugins": [
"vue", // eslint-plugin-vue
"@typescript-eslint", // @typescript-eslint/eslint-plugin
"import", // eslint-plugin-import
"prettier" // eslint-plugin-prettier
]
}插件命名规则:
eslint-plugin-前缀可以省略@scope/eslint-plugin-name→@scope/name@scope/eslint-plugin→@scope
影响对比:
// ❌ 未安装/配置插件
{
"rules": {
"vue/no-unused-vars": "error" // ❌ 错误:找不到 vue 插件
}
}
// ✅ 配置插件
{
"plugins": ["vue"],
"rules": {
"vue/no-unused-vars": "error" // ✅ 正确
}
}常用插件:
# Vue
npm install --save-dev eslint-plugin-vue
# TypeScript
npm install --save-dev @typescript-eslint/eslint-plugin @typescript-eslint/parser
# React
npm install --save-dev eslint-plugin-react eslint-plugin-react-hooks
# Import
npm install --save-dev eslint-plugin-import
# Prettier
npm install --save-dev eslint-plugin-prettier eslint-config-prettier1.6 parser#
作用:指定解析器,支持不同的语法。
{
"parser": "@typescript-eslint/parser"
}常用解析器:
// 默认:espree(ESLint 内置)
// 支持标准 JavaScript
// TypeScript
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
}
}
// Vue
{
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser" // 解析 <script> 标签内容
}
}
// Babel
{
"parser": "@babel/eslint-parser",
"parserOptions": {
"requireConfigFile": false
}
}影响对比:
// ❌ 默认解析器无法解析 TypeScript
interface User {
name: string;
} // ❌ 语法错误
// ✅ 使用 TypeScript 解析器
{
"parser": "@typescript-eslint/parser"
}
interface User {
name: string;
} // ✅ 正确解析
1.7 parserOptions#
作用:配置解析器选项。
{
"parserOptions": {
"ecmaVersion": 2021, // ECMAScript 版本
"sourceType": "module", // 模块类型
"ecmaFeatures": {
"jsx": true, // 启用 JSX
"globalReturn": false, // 允许全局 return
"impliedStrict": true // 启用严格模式
}
}
}详细说明:
{
"parserOptions": {
// ECMAScript 版本
// 可选值: 3, 5(默认), 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
// 或 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024
// 或 "latest"(自动使用最新支持的版本)
"ecmaVersion": "latest",
// 模块类型
"sourceType": "module", // "script"(默认) 或 "module"
// ECMAScript 特性
"ecmaFeatures": {
"jsx": true, // 启用 JSX 解析
"globalReturn": false, // 允许全局作用域使用 return
"impliedStrict": false // 启用全局严格模式(ecmaVersion >= 5)
},
// TypeScript 特定(需要 @typescript-eslint/parser)
"project": "./tsconfig.json", // TypeScript 配置文件
"tsconfigRootDir": __dirname // tsconfig.json 所在目录
}
}影响对比:
// sourceType: "script"(默认)
import { foo } from "./foo"; // ❌ 错误:不支持 import
// sourceType: "module"
import { foo } from "./foo"; // ✅ 正确
// ecmaFeatures.jsx: false
const element = <div>Hello</div>; // ❌ 语法错误
// ecmaFeatures.jsx: true
const element = <div>Hello</div>; // ✅ 正确解析1.8 rules#
作用:配置具体的检查规则。
{
"rules": {
"semi": ["error", "always"], // 要求分号
"quotes": ["error", "single"], // 使用单引号
"no-console": "warn", // 警告 console
"no-unused-vars": "error", // 错误:未使用的变量
"prefer-const": "error", // 优先使用 const
"@typescript-eslint/no-explicit-any": "off" // 关闭规则
}
}规则级别:
{
"rules": {
// 字符串形式
"semi": "off", // 关闭规则
"semi": "warn", // 警告
"semi": "error", // 错误
// 数字形式(不推荐)
"semi": 0, // 关闭
"semi": 1, // 警告
"semi": 2, // 错误
// 数组形式(带配置)
"semi": ["error", "always"], // 错误级别 + 配置
"quotes": ["error", "single", { "avoidEscape": true }]
}
}影响对比:
// semi: "off"
const name = "John"; // ✅ 不报错
// semi: "warn"
const name = "John"; // ⚠️ 警告:Missing semicolon
// semi: "error"
const name = "John"; // ❌ 错误:Missing semicolon
// semi: ["error", "always"]
const name = "John"; // ❌ 错误
const name = "John"; // ✅ 正确
// semi: ["error", "never"]
const name = "John"; // ❌ 错误
const name = "John"; // ✅ 正确
1.9 overrides#
作用:为特定文件应用不同的配置。
{
"rules": {
"no-console": "error"
},
"overrides": [
{
"files": ["*.test.js", "*.spec.js"],
"env": {
"jest": true
},
"rules": {
"no-console": "off" // 测试文件允许 console
}
},
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser",
"rules": {
"@typescript-eslint/no-unused-vars": "error"
}
}
]
}使用场景:
{
"overrides": [
// Vue 文件
{
"files": ["*.vue"],
"parser": "vue-eslint-parser"
},
// 配置文件
{
"files": ["*.config.js", ".*rc.js"],
"env": {
"node": true
},
"rules": {
"no-console": "off"
}
},
// TypeScript 文件
{
"files": ["*.ts", "*.tsx"],
"extends": ["plugin:@typescript-eslint/recommended"],
"rules": {
"no-undef": "off" // TS 已经检查
}
}
]
}二、常用规则详解#
2.1 代码质量规则#
no-unused-vars#
作用:禁止未使用的变量。
{
"rules": {
"no-unused-vars": ["error", {
"vars": "all", // 检查所有变量(包括全局)
"args": "after-used", // 只检查最后一个使用参数之后的参数
"ignoreRestSiblings": true, // 忽略解构中的剩余兄弟属性
"argsIgnorePattern": "^_", // 忽略以 _ 开头的参数
"varsIgnorePattern": "^_" // 忽略以 _ 开头的变量
}]
}
}配置选项说明:
| 选项 | 可选值 | 说明 |
|---|---|---|
vars | "all" / "local" | all:检查所有变量;local:只检查局部变量 |
args | "after-used" / "all" / "none" | after-used:只检查最后使用参数之后的;all:检查所有参数;none:不检查参数 |
ignoreRestSiblings | true / false | 是否忽略解构中剩余兄弟属性 |
argsIgnorePattern | 正则表达式 | 忽略匹配的参数名 |
varsIgnorePattern | 正则表达式 | 忽略匹配的变量名 |
caughtErrors | "all" / "none" | 是否检查 catch 块中的错误参数 |
caughtErrorsIgnorePattern | 正则表达式 | 忽略匹配的 catch 错误参数名 |
影响对比:
// ❌ 错误
const unused = 10; // ❌ 'unused' is assigned a value but never used
// args: "after-used" 时
function calculate(a, b, c, d) {
// ❌ 'c' 和 'd' 在最后使用的 'b' 之后,会报错
return a + b;
}
// ✅ 正确
const used = 10;
console.log(used);
function calculate(a, b) {
// 只声明使用的参数
return a + b;
}
// 使用下划线前缀表示故意不使用(配合 argsIgnorePattern: "^_")
function calculate(a, b, _c) {
// ✅ 正确
return a + b;
}
// 解构中的剩余兄弟属性(配合 ignoreRestSiblings: true)
const { used, ...rest } = obj; // ✅ rest 即使未使用也不报错
console.log(used);no-undef#
作用:禁止使用未声明的变量。
{
"rules": {
"no-undef": "error"
}
}影响对比:
// ❌ 错误
console.log(undeclaredVar); // ❌ 'undeclaredVar' is not defined
// ✅ 正确
const declaredVar = 10;
console.log(declaredVar);
// 或在 globals 中声明
{
"globals": {
"myGlobal": "readonly"
}
}
console.log(myGlobal); // ✅ 正确
no-const-assign#
作用:禁止修改 const 声明的变量。
{
"rules": {
"no-const-assign": "error"
}
}影响对比:
// ❌ 错误
const PI = 3.14;
PI = 3.14159; // ❌ 'PI' is constant
// ✅ 正确
let value = 10;
value = 20; // ✅ 可以修改 let
2.2 最佳实践规则#
prefer-const#
作用:优先使用 const。
{
"rules": {
"prefer-const": ["error", {
"destructuring": "all", // 解构赋值全用 const
"ignoreReadBeforeAssign": false
}]
}
}影响对比:
// ❌ 错误
let name = "John"; // ❌ 'name' is never reassigned
console.log(name);
// ✅ 正确
const name = "John"; // ✅ 使用 const
console.log(name);
let count = 0; // ✅ 需要修改,使用 let
count++;eqeqeq#
作用:要求使用 === 和 !==。
{
"rules": {
"eqeqeq": ["error", "always"]
}
}影响对比:
// ❌ 错误
if (x == 10) {} // ❌ Expected '===' and instead saw '=='
if (x != null) {} // ❌ Expected '!==' and instead saw '!='
// ✅ 正确
if (x === 10) {} // ✅
if (x !== null) {} // ✅
// 特殊情况:允许与 null 比较
{
"rules": {
"eqeqeq": ["error", "always", { "null": "ignore" }]
}
}
if (x == null) {} // ✅ 允许 x == null 检查 null 和 undefined
no-var#
作用:禁止使用 var。
{
"rules": {
"no-var": "error"
}
}影响对比:
// ❌ 错误
var name = "John"; // ❌ Unexpected var, use let or const instead
// ✅ 正确
const name = "John"; // ✅
let count = 0; // ✅
2.3 代码风格规则#
semi#
作用:要求或禁止分号。
{
"rules": {
"semi": ["error", "always"] // 或 "never"
}
}影响对比:
// semi: ["error", "always"]
const name = "John"; // ❌ Missing semicolon
const name = "John"; // ✅
// semi: ["error", "never"]
const name = "John"; // ❌ Extra semicolon
const name = "John"; // ✅
quotes#
作用:强制使用一致的引号。
{
"rules": {
"quotes": ["error", "single", {
"avoidEscape": true, // 避免转义
"allowTemplateLiterals": true // 允许模板字符串
}]
}
}影响对比:
// quotes: ["error", "single"]
const name = "John"; // ❌ Strings must use singlequote
const name = "John"; // ✅
// avoidEscape: true
const text = "It's ok"; // ❌ 需要转义
const text = "It's ok"; // ✅ 避免转义,允许双引号
const text = `It's ok`; // ✅ 模板字符串
// allowTemplateLiterals: true
const name = `John`; // ✅ 允许模板字符串
const greeting = `Hello ${name}`; // ✅
indent#
作用:强制使用一致的缩进。
{
"rules": {
"indent": ["error", 2, {
"SwitchCase": 1, // switch case 缩进
"VariableDeclarator": 1 // 变量声明缩进
}]
}
}影响对比:
// indent: ["error", 2]
function greet() {
console.log("Hello"); // ❌ Expected indentation of 2 spaces but found 4
}
function greet() {
console.log("Hello"); // ✅
}
// SwitchCase: 1
switch (x) {
case 1: // ❌ Expected indentation of 2 spaces
break;
}
switch (x) {
case 1: // ✅
break;
}2.4 Vue 特定规则#
vue/multi-word-component-names#
作用:要求组件名为多个单词。
{
"rules": {
"vue/multi-word-component-names": ["error", {
"ignores": ["index", "App"]
}]
}
}影响对比:
<!-- ❌ 错误 -->
<script>
export default {
name: "Button", // ❌ Component name should be multi-word
};
</script>
<!-- ✅ 正确 -->
<script>
export default {
name: "BaseButton", // ✅ 多个单词
};
</script>
<!-- 特殊情况 -->
<script>
export default {
name: "App", // ✅ 在 ignores 中
};
</script>vue/html-indent#
作用:Vue 模板缩进。
{
"rules": {
"vue/html-indent": ["error", 2, {
"attribute": 1,
"baseIndent": 1
}]
}
}2.5 TypeScript 特定规则#
@typescript-eslint/no-explicit-any#
作用:禁止使用 any 类型。
{
"rules": {
"@typescript-eslint/no-explicit-any": "error"
}
}影响对比:
// ❌ 错误
function process(data: any) {
// ❌ Unexpected any
return data;
}
// ✅ 正确
function process(data: unknown) {
// ✅ 使用 unknown
return data;
}
function process<T>(data: T): T {
// ✅ 使用泛型
return data;
}@typescript-eslint/no-unused-vars#
作用:TypeScript 版本的未使用变量检查。
{
"rules": {
"no-unused-vars": "off", // 关闭基础规则,避免与 TS 规则冲突
"@typescript-eslint/no-unused-vars": ["error", {
"args": "all", // 检查所有参数
"argsIgnorePattern": "^_", // 忽略 _ 开头的参数
"varsIgnorePattern": "^_", // 忽略 _ 开头的变量
"caughtErrors": "all", // 检查 catch 中的错误参数
"caughtErrorsIgnorePattern": "^_", // 忽略 _ 开头的错误参数
"destructuredArrayIgnorePattern": "^_", // 忽略解构数组中 _ 开头的元素
"ignoreRestSiblings": true // 忽略剩余兄弟属性
}]
}
}三、完整推荐配置#
3.1 纯 JavaScript 项目#
// .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2022: true,
node: true,
},
extends: ["eslint:recommended"],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
rules: {
// 代码质量
"no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
// 最佳实践
"prefer-const": "error",
"no-var": "error",
eqeqeq: ["error", "always", { null: "ignore" }],
// 代码风格
semi: ["error", "always"],
quotes: ["error", "single", { avoidEscape: true }],
indent: ["error", 2, { SwitchCase: 1 }],
"comma-dangle": ["error", "never"],
},
};3.2 Vue 3 + TypeScript 项目#
// .eslintrc.cjs
module.exports = {
root: true,
env: {
browser: true,
es2022: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:vue/vue3-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended", // 必须放在最后
],
parser: "vue-eslint-parser",
parserOptions: {
ecmaVersion: "latest",
parser: "@typescript-eslint/parser",
sourceType: "module",
project: "./tsconfig.json",
extraFileExtensions: [".vue"],
},
plugins: ["vue", "@typescript-eslint"],
rules: {
// Vue 规则
"vue/multi-word-component-names": [
"error",
{
ignores: ["index", "App", "[id]"],
},
],
"vue/component-name-in-template-casing": ["error", "PascalCase"],
"vue/component-definition-name-casing": ["error", "PascalCase"],
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "never",
component: "always",
},
},
],
// TypeScript 规则
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
},
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/explicit-module-boundary-types": "off",
// 通用规则
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
},
overrides: [
// 配置文件
{
files: ["*.config.js", "*.config.ts"],
rules: {
"no-console": "off",
},
},
],
};3.3 React + TypeScript 项目#
// .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2022: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
project: "./tsconfig.json",
},
plugins: ["react", "react-hooks", "@typescript-eslint"],
settings: {
react: {
version: "detect", // 自动检测 React 版本
},
},
rules: {
// React 规则
"react/react-in-jsx-scope": "off", // React 17+ 不需要
"react/prop-types": "off", // 使用 TypeScript
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// TypeScript 规则
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "warn",
// 通用规则
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
},
};3.4 Node.js 项目#
// .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
es2022: true,
},
extends: ["eslint:recommended"],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
rules: {
// Node.js 特定
"no-console": "off", // Node.js 允许 console
"no-process-exit": "error",
// 代码质量
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
},
],
"prefer-const": "error",
"no-var": "error",
},
};四、与 Prettier 集成#
4.1 安装依赖#
npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier4.2 配置 ESLint#
// .eslintrc.js
module.exports = {
extends: [
"eslint:recommended",
"plugin:prettier/recommended", // 必须放在最后
],
};4.3 配置 Prettier#
// .prettierrc.json
{
"semi": true,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "es5",
"arrowParens": "always"
}4.4 package.json 脚本#
{
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx,.vue --fix",
"format": "prettier --write ."
}
}五、忽略文件#
5.1 .eslintignore#
# 依赖
node_modules
pnpm-lock.yaml
package-lock.json
# 构建产物
dist
build
.next
.nuxt
out
coverage
# 缓存
.cache
*.log
# 自动生成的文件
*.min.js
auto-imports.d.ts
components.d.ts
# 配置文件
.env
.env.*5.2 在配置文件中忽略#
module.exports = {
ignorePatterns: ["dist", "node_modules", "*.min.js"],
};六、常见问题和最佳实践#
6.1 ESLint vs Prettier#
区别:
| 工具 | 职责 | 示例 |
|---|---|---|
| ESLint | 代码质量 + 部分风格 | 未使用变量、潜在 bug、部分格式 |
| Prettier | 代码格式化 | 缩进、引号、分号、换行 |
推荐做法:
- 使用 ESLint 检查代码质量
- 使用 Prettier 格式化代码
- 使用
eslint-config-prettier禁用 ESLint 中与 Prettier 冲突的规则
module.exports = {
extends: [
"eslint:recommended",
"plugin:prettier/recommended", // 禁用冲突规则并启用 Prettier 规则
],
};6.2 性能优化#
1. 使用缓存:
{
"scripts": {
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint"
}
}2. 限制检查文件:
{
"scripts": {
"lint": "eslint src --ext .js,.jsx,.ts,.tsx"
}
}3. 使用 ignorePatterns:
module.exports = {
ignorePatterns: ["dist", "node_modules", "*.min.js"],
};6.3 VS Code 集成#
.vscode/settings.json:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}6.4 Git Hooks 集成#
使用 husky + lint-staged:
npm install --save-dev husky lint-staged
npx husky initpackage.json:
{
"lint-staged": {
"*.{js,jsx,ts,tsx,vue}": ["eslint --fix", "prettier --write"]
}
}.husky/pre-commit:
#!/usr/bin/env sh
npx lint-staged6.5 CI 中运行#
.github/workflows/lint.yml:
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- run: npm ci
- run: npm run lint6.6 迁移现有项目#
步骤:
# 1. 安装 ESLint
npm install --save-dev eslint
# 2. 初始化配置
npx eslint --init
# 3. 检查问题
npm run lint
# 4. 自动修复
npm run lint:fix
# 5. 手动修复剩余问题
# 6. 提交更改
git add .
git commit -m "chore: 添加 ESLint 配置"6.7 禁用规则的正确方式#
文件级别:
/* eslint-disable */
// 整个文件禁用
/* eslint-enable */
// 重新启用
行级别:
// eslint-disable-next-line
const unused = 10;
const unused = 10; // eslint-disable-line
// 禁用特定规则
// eslint-disable-next-line no-console
console.log("Debug");块级别:
/* eslint-disable no-console */
console.log("Debug 1");
console.log("Debug 2");
/* eslint-enable no-console */6.8 常见错误解决#
1. Parsing error: Cannot find module ‘@typescript-eslint/parser’
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin2. ‘module’ is not defined
// .eslintrc.js
module.exports = {
env: {
node: true, // 添加 node 环境
},
};3. ESLint 和 Prettier 冲突
npm install --save-dev eslint-config-prettiermodule.exports = {
extends: [
"eslint:recommended",
"plugin:prettier/recommended", // 必须放在最后
],
};七、总结#
必须配置的选项#
- root:
true- 限制配置查找 - env - 声明运行环境
- extends - 继承推荐配置
- parser - TypeScript/Vue 项目必需
- rules - 根据团队规范自定义
推荐工作流#
- 使用
eslint:recommended作为基础 - 根据框架添加对应插件(Vue/React/TypeScript)
- 集成 Prettier 处理代码格式
- 配置 Git Hooks 自动检查
- 在 CI 中运行 lint
常用命令#
# 检查代码
npx eslint .
# 自动修复
npx eslint . --fix
# 检查特定文件
npx eslint src/index.js
# 使用缓存
npx eslint . --cache
# 输出 JSON 格式
npx eslint . --format json
# 检查并报告未使用的禁用指令
npx eslint . --report-unused-disable-directives学习建议#
- 从
eslint:recommended开始 - 逐步添加规则,不要一次性开启所有
- 理解每个规则的作用,而不是盲目配置
- 使用
--fix自动修复可修复的问题 - 定期更新 ESLint 和插件版本
八、ESLint 9.x 新特性预览#
ESLint 9.x 引入了全新的**扁平化配置(Flat Config)**系统,使用 eslint.config.js 替代 .eslintrc.* 文件。
8.1 主要变化#
| 特性 | ESLint 8.x | ESLint 9.x |
|---|---|---|
| 配置文件 | .eslintrc.js / .eslintrc.json | eslint.config.js |
| 配置格式 | 对象形式 | 数组形式 |
| env 选项 | 支持 | 移除,使用 globals 包代替 |
| plugins 格式 | 字符串数组 | 对象形式 |
| extends | 支持 | 移除,直接使用配置数组 |
8.2 扁平化配置示例#
// eslint.config.js
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import pluginVue from "eslint-plugin-vue";
export default [
// 推荐配置
js.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs["flat/recommended"],
// 自定义配置
{
files: ["**/*.{js,ts,vue}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
...globals.browser,
...globals.node,
},
},
rules: {
"no-console": "warn",
"no-unused-vars": "error",
},
},
// 忽略文件
{
ignores: ["dist/**", "node_modules/**"],
},
];8.3 迁移建议#
如果你正在使用 ESLint 8.x,可以通过以下命令检查配置迁移:
# 安装迁移工具
npx @eslint/migrate-config .eslintrc.js
# 或手动迁移
# 参考官方迁移指南:https://eslint.org/docs/latest/use/configure/migration-guide