ESLint从入门到实战


引言

作为前端开发者,你是否遇到过这样的情况:团队成员写出的代码风格各异,有人喜欢用分号,有人不用;有人用双引号,有人用单引号;代码评审时总是在纠结这些格式问题而不是业务逻辑?或者在大型项目中,因为一个未定义的变量导致生产环境报错?

ESLint 就是为了解决这些问题而生的。它不仅能统一代码风格,更重要的是能在开发阶段就发现潜在的错误,提高代码质量和开发效率。

本文将从零开始,带你全面掌握 ESLint 的使用,从基础配置到高级定制,从个人项目到团队协作,让你成为 ESLint 的专家。

什么是ESLint?

定义与作用

ESLint 是一个开源的 JavaScript 代码静态分析工具,由 Nicholas C. Zakas 在 2013 年创建。它的主要作用是:

  1. 代码质量检查:识别有问题的模式或不符合特定规则的代码
  2. 代码风格统一:强制执行一致的代码风格
  3. 错误预防:在运行前捕获潜在的错误
  4. 最佳实践提醒:推广 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 会问你几个问题:

  1. 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(检查语法、发现问题并强制代码风格)
  2. What type of modules does your project use?

    • JavaScript modules (import/export)
    • CommonJS (require/exports)
    • None of these
  3. Which framework does your project use?

    • React
    • Vue.js
    • None of these
  4. Does your project use TypeScript? Yes/No

  5. Where does your code run?

    • Browser
    • Node
  6. 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 支持多种配置文件格式,优先级从高到低:

  1. .eslintrc.js
  2. .eslintrc.cjs
  3. .eslintrc.yaml.eslintrc.yml
  4. .eslintrc.json
  5. 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集成

  1. 安装ESLint插件

    • 在扩展商店搜索 "ESLint"
    • 安装官方的 ESLint 插件
  2. 配置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集成

  1. 打开 Settings/Preferences
  2. 导航到 Languages & Frameworks > JavaScript > Code Quality Tools > ESLint
  3. 勾选 "Automatic ESLint configuration"
  4. 配置 "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/"
  }
}
相关推荐
qq_411671988 分钟前
webpack 如何区分开发环境和生产环境
前端·webpack·node.js
brzhang13 分钟前
Kotlin Multiplatform (KMP) vs. Flutter:谁才是下一代跨平台开发的真正王者?
前端·后端·架构
xw518 分钟前
uni-app项目process is not defined
前端·uni-app
独立开阀者_FwtCoder39 分钟前
三行CSS代码把网页像素化
前端·javascript·github
用户37743486002201 小时前
从渲染集合到模块学习
前端
安心不心安1 小时前
React状态管理——redux-saga异步操作
前端·javascript·react.js
猩猩程序员1 小时前
bzip2 crate 从 C 切换为 100% Rust 实现
前端
500佰1 小时前
总结前端三年 理想滚烫与现实的冰冷碰撞
前端
全栈小51 小时前
【前端】Vue3+elementui+ts,给标签设置样式属性style时,提示type check failed for prop,再次请出DeepSeek来解答
前端·elementui
哪 吒1 小时前
突破亚马逊壁垒,Web Unlocker API 助您轻松获取数据
前端·网络·python·网络安全