ESLint从入门到实战_.eslintrc.js的globals
引言
作为前端开发者,你是否遇到过这样的情况:团队成员写出的代码风格各异,有人喜欢用分号,有人不用;有人用双引号,有人用单引号;代码评审时总是在纠结这些格式问题而不是业务逻辑?或者在大型项目中,因为一个未定义的变量导致生产环境报错?
ESLint 就是为了解决这些问题而生的。它不仅能统一代码风格,更重要的是能在开发阶段就发现潜在的错误,提高代码质量和开发效率。
本文将从零开始,带你全面掌握 ESLint 的使用,从基础配置到高级定制,从个人项目到团队协作,让你成为 ESLint 的专家。
什么是ESLint?
定义与作用
ESLint 是一个开源的 JavaScript 代码静态分析工具,由 Nicholas C. Zakas 在 2013 年创建。它的主要作用是:
- 代码质量检查:识别有问题的模式或不符合特定规则的代码
- 代码风格统一:强制执行一致的代码风格
- 错误预防:在运行前捕获潜在的错误
- 最佳实践提醒:推广 JavaScript 最佳实践
核心特性
- 完全可配置:所有规则都可以开启/关闭,每个规则都有多个设置选项
- 插件化架构:可以通过插件扩展功能,支持 TypeScript、React、Vue 等
- 支持多种配置格式:JSON、YAML、JavaScript 等
- IDE 集成:主流编辑器都有相应插件
- 自动修复:大部分格式问题可以自动修复
安装与基础配置
安装ESLint
# 全局安装(不推荐)npm install -g eslint# 项目内安装(推荐)npm install --save-dev eslint# 使用 yarnyarn add --dev eslint# 使用 pnpmpnpm add -D eslint
初始化配置
# 交互式创建配置文件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
为例:
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(环境配置)
定义代码运行的环境,影响全局变量的可用性:
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(扩展配置)
继承其他的配置文件或预设规则集:
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 使用的解析器:
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 功能的插件:
module.exports = { plugins: [ \'@typescript-eslint\', // TypeScript 插件 \'react\', // React 插件 \'react-hooks\', // React Hooks 插件 \'import\', // import/export 插件 \'jsx-a11y\', // 无障碍访问插件 \'prettier\' // Prettier 插件 ]};
5. rules(规则配置)
这是 ESLint 的核心,定义具体的检查规则:
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(全局变量)
定义额外的全局变量:
module.exports = { globals: { myCustomGlobal: \'readonly\', // 只读 anotherGlobal: \'writable\', // 可写 $: \'readonly\', // jQuery _: \'readonly\' // Lodash }};
2. overrides(覆盖配置)
为特定文件或目录设置不同的规则:
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(忽略模式)
指定要忽略的文件和目录:
module.exports = { ignorePatterns: [ \'dist/\', \'build/\', \'node_modules/\', \'*.min.js\', \'coverage/\' ]};
常用规则详解
代码质量规则
1. 变量相关
{ // 禁止使用未声明的变量 \'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. 函数相关
{ // 要求或禁止使用命名的 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. 对象和数组
{ // 禁止对象字面量中出现重复的 key \'no-dupe-keys\': \'error\', // 禁止数组中出现重复的元素 \'no-dupe-args\': \'error\', // 强制对象字面量属性名称使用一致的引号 \'quote-props\': [\'error\', \'as-needed\'], // 要求对象字面量简写语法 \'object-shorthand\': [\'error\', \'always\']}
代码风格规则
1. 空格和缩进
{ // 强制使用一致的缩进 \'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. 引号和分号
{ // 强制使用一致的引号 \'quotes\': [\'error\', \'single\', { avoidEscape: true, // 避免转义 allowTemplateLiterals: true // 允许模板字符串 }], // 要求或禁止使用分号 \'semi\': [\'error\', \'always\'], // 强制分号之前和之后使用一致的空格 \'semi-spacing\': [\'error\', { before: false, after: true }]}
ES6+ 规则
{ // 要求使用 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项目配置
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项目配置
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项目配置
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\' }};
命令行使用
基本命令
# 检查单个文件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 tablenpx eslint src/ --format json
高级命令选项
# 忽略 .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 脚本配置
{ \"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
{ \"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集成
# 安装相关包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集成
# 安装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集成
// webpack.config.jsconst ESLintPlugin = require(\'eslint-webpack-plugin\');module.exports = { plugins: [ new ESLintPlugin({ extensions: [\'js\', \'jsx\', \'ts\', \'tsx\'], fix: true, cache: true }) ]};
自定义规则开发
创建简单的自定义规则
// rules/no-console-log.jsmodule.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); } }); } } }; }};
使用自定义规则
// .eslintrc.jsmodule.exports = { rules: { \'local/no-console-log\': \'error\' }, plugins: [\'local\']};// eslint-plugin-local/index.jsmodule.exports = { rules: { \'no-console-log\': require(\'./rules/no-console-log\') }};
性能优化
缓存配置
# 启用缓存npx eslint src/ --cache# 指定缓存文件位置npx eslint src/ --cache --cache-location node_modules/.cache/eslint
并行处理
{ \"scripts\": { \"lint:parallel\": \"eslint src/ --cache --fix --max-warnings 0\" }}
忽略文件配置
# .eslintignorenode_modules/dist/build/coverage/*.min.js*.bundle.jspublic/
团队协作最佳实践
1. 统一配置管理
// eslint-config-company/index.jsmodule.exports = { extends: [ \'eslint:recommended\', \'@typescript-eslint/recommended\' ], rules: { // 公司统一规则 \'indent\': [\'error\', 2], \'quotes\': [\'error\', \'single\'], \'semi\': [\'error\', \'always\'] }};// 项目中使用// .eslintrc.jsmodule.exports = { extends: [\'@company/eslint-config\']};
2. 渐进式引入
// 第一阶段:只启用错误级别规则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 集成
# .github/workflows/lint.ymlname: Linton: [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
解决:检查解析器配置,确保支持使用的语法特性
module.exports = { parser: \'@babel/eslint-parser\', parserOptions: { ecmaVersion: 2021, sourceType: \'module\', requireConfigFile: false }};
2. 规则冲突
问题:ESLint 和 Prettier 规则冲突
解决:使用 eslint-config-prettier
module.exports = { extends: [ \'eslint:recommended\', \'prettier\' // 必须放在最后,覆盖冲突规则 ]};
3. 性能问题
问题:ESLint 运行很慢
解决:
- 启用缓存:
--cache
- 使用 .eslintignore 忽略不必要的文件
- 考虑使用 eslint_d
# 安装 eslint_d(ESLint 守护进程)npm install -g eslint_d# 使用 eslint_d 替代 eslinteslint_d src/
4. 内存溢出
问题:JavaScript heap out of memory
解决:增加 Node.js 内存限制
{ \"scripts\": { \"lint\": \"node --max-old-space-size=4096 node_modules/.bin/eslint src/\" }}