eslint 配置选项

Nov 6 · 120min

什么是 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

配置文件

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" 或未指定 → CommonJS
  • package.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,         // process, __dirname, require 等
    "es6": true,          // ES6 全局变量(Promise, Set, Map)
    "es2020": true,       // ES2020 全局变量(BigInt, globalThis)
    "es2021": true,       // ES2021 全局变量
    "es2022": true,       // ES2022 全局变量
    "worker": true,       // Web Worker 全局变量
    "serviceworker": true,// Service Worker 全局变量
    "commonjs": true,     // CommonJS 全局变量(module, exports)
    "shared-node-browser": true,  // Node.js 和浏览器共享的全局变量
    "jest": true,         // Jest 全局变量(describe, test, expect)
    "mocha": true,        // Mocha 全局变量(describe, it, before)
    "jquery": true        // jQuery 全局变量($, jQuery)
  }
}

影响对比

// ❌ 未配置 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" / "off":只读,不可修改
  • "writable" / "on":可读写

影响对比

// ❌ 未声明全局变量
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-prettier

1.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 版本
    "ecmaVersion": 2021,  // 3, 5, 6/2015, 7/2016, ..., 2021, "latest"
    
    // 模块类型
    "sourceType": "module",  // "script" 或 "module"
    
    // ECMAScript 特性
    "ecmaFeatures": {
      "jsx": true,              // 启用 JSX
      "globalReturn": false,    // 允许全局 return
      "impliedStrict": false    // 启用严格模式
    },
    
    // 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  // 忽略剩余参数
    }]
  }
}

影响对比

// ❌ 错误
const unused = 10;  // ❌ 'unused' is assigned a value but never used

function calculate(a, b, c) {  // ❌ 'c' is defined but never used
  return a + b;
}

// ✅ 正确
const used = 10;
console.log(used);

function calculate(a, b) {  // 只声明使用的参数
  return a + b;
}

// 使用下划线前缀表示故意不使用
function calculate(a, b, _c) {  // ✅ 正确
  return a + b;
}

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",  // 关闭基础规则
    "@typescript-eslint/no-unused-vars": ["error", {
      "argsIgnorePattern": "^_"  // 忽略 _ 开头的参数
    }]
  }
}

三、完整推荐配置

3.1 纯 JavaScript 项目

// .eslintrc.js
module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended'
  ],
  parserOptions: {
    ecmaVersion: 2021,
    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,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended'  // 必须放在最后
  ],
  parser: 'vue-eslint-parser',
  parserOptions: {
    ecmaVersion: 2021,
    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,
    es2021: 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: 2021,
    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,
    es2021: true
  },
  extends: [
    'eslint:recommended'
  ],
  parserOptions: {
    ecmaVersion: 2021,
    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-prettier

4.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代码格式化缩进、引号、分号、换行

推荐做法

  1. 使用 ESLint 检查代码质量
  2. 使用 Prettier 格式化代码
  3. 使用 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 init

package.json

{
  "lint-staged": {
    "*.{js,jsx,ts,tsx,vue}": [
      "eslint --fix",
      "prettier --write"
    ]
  }
}

.husky/pre-commit

#!/usr/bin/env sh
npx lint-staged

6.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 lint

6.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-plugin

2. 'module' is not defined

// .eslintrc.js
module.exports = {
  env: {
    node: true  // 添加 node 环境
  }
};

3. ESLint 和 Prettier 冲突

npm install --save-dev eslint-config-prettier
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended'  // 必须放在最后
  ]
};

七、总结

必须配置的选项

  1. root: true - 限制配置查找
  2. env - 声明运行环境
  3. extends - 继承推荐配置
  4. parser - TypeScript/Vue 项目必需
  5. rules - 根据团队规范自定义

推荐工作流

  1. 使用 eslint:recommended 作为基础
  2. 根据框架添加对应插件(Vue/React/TypeScript)
  3. 集成 Prettier 处理代码格式
  4. 配置 Git Hooks 自动检查
  5. 在 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

学习建议

  1. eslint:recommended 开始
  2. 逐步添加规则,不要一次性开启所有
  3. 理解每个规则的作用,而不是盲目配置
  4. 使用 --fix 自动修复可修复的问题
  5. 定期更新 ESLint 和插件版本

参考资源

CC BY-NC-SA 4.0 2024-PRESENT © hujiacheng