ESLint 配置与实践指南
ESLint 是一款强大的 JavaScript 静态代码分析工具,旨在帮助开发者发现代码中的潜在问题并强制执行编码风格的一致性。
ESLint 配置
首先,全局安装 ESLint:
npm install -g eslint
接着,初始化 ESLint 配置:
eslint --init
在交互式配置过程中,您需要做出以下选择:
- 选择检查语法并查找问题。
- 选择 JavaScript 模块(ES Modules)。
- 根据您的项目选择使用的框架(如 React 或 Vue)。
- 选择您的项目使用的语言(TypeScript 或 JavaScript)。
- 选择代码的运行环境(浏览器、Node.js 等)。
- 选择是否立即安装所需的依赖。
- 选择您偏好的包管理器(npm 或 yarn)。
配置文件
初始化完成后,项目根目录下会生成配置文件(如 .eslintrc.js 或 eslint.config.mjs)。
React 项目配置示例 (eslint.config.mjs)
import globals from "globals";
import pluginJs from "@eslint/js";
import pluginReactConfig from "eslint-plugin-react/configs/recommended.js";
export default [
{
files: ["**/*.{js,mjs,cjs,jsx}"],
languageOptions: {
parserOptions: {
ecmaFeatures: { jsx: true }
},
globals: { ...globals.browser, ...globals.node }
},
plugins: {
react: pluginReactConfig
},
rules: {
...pluginJs.configs.recommended.rules,
...pluginReactConfig.rules
// 您可以在此处添加或覆盖特定规则
}
}
];
通用 ESLint 规则配置 (.eslintrc.js)
以下是一个通用的 ESLint 规则配置示例,您可以根据项目需求进行调整。规则级别:off (关闭), warn (警告), error (错误)。
/**
* ESLint 规则配置
* off 或 0: 关闭规则
* warn 或 1: 开启规则,警告级别
* error 或 2: 开启规则,错误级别
*/
module.exports = {
parser: '@babel/eslint-parser', // 或者使用 esquery, esprima 等
parserOptions: {
ecmaVersion: 2021, // 支持的 ECMAScript 语法的版本
sourceType: 'module', // 允许使用 import/export 语法
ecmaFeatures: {
jsx: true, // 启用 JSX 支持
globalReturn: true, // 允许在全局作用域使用 return 语句
impliedStric t: true, // 启用严格模式
},
},
env: {
browser: true, // 启用浏览器环境全局变量
node: true, // 启用 Node.js 环境全局变量
commonjs: true, // 启用 CommonJS 全局变量
es6: true, // 启用 ES6 全局变量
es2017: true, // 启用 ES2017 全局变量
es2020: true, // 启用 ES2020 全局变量
jest: true, // 启用 Jest 测试框架全局变量
},
// 指定根目录,防止 ESLint 向上搜索配置文件
root: true,
rules: {
// --- 潜在错误 ---
'for-direction': 'error', // 禁止 for 循环方向错误
'getter-return': ['error', { allowImplicit: false }], // getter 必须有返回值
'no-await-in-loop': 'off', // 允许在循环中使用 await (根据项目需求调整)
'no-compare-neg-zero': 'error', // 禁止与负零比较
'no-cond-assign': ['error', 'except-parens'], // 禁止在条件判断中使用赋值语句,除非用括号包围
'no-console': 'off', // 允许使用 console (根据项目需求调整)
'no-constant-condition': ['error', { checkLoops: false }], // 禁止常量作为条件判断,除非是循环条件
'no-control-regex': 'off', // 允许在正则表达式中使用控制字符 (根据项目需求调整)
'no-debugger': 'error', // 禁止使用 debugger
'no-dupe-args': 'error', // 禁止函数参数重名
'no-dupe-keys': 'error', // 禁止对象属性重名
'no-duplicate-case': 'error', // 禁止 switch 语句中重复的 case
'no-empty': ['error', { allowEmptyCatch: true }], // 禁止空代码块,允许 catch 为空
'no-empty-character-class': 'error', // 禁止正则表达式使用空的字符集
'no-ex-assign': 'error', // 禁止重新赋值 catch 参数
'no-extra-boolean-cast': 'error', // 禁止不必要的布尔值转换
'no-extra-parens': ['error', 'functions'], // 禁止不必要的括号,允许函数表达式
'no-extra-semi': 'error', // 禁止多余的分号
'no-func-assign': 'error', // 禁止重新赋值函数声明
'no-inner-declarations': ['error', 'both'], // 禁止在 if 块内声明函数
'no-invalid-regexp': 'error', // 禁止使用无效的正则表达式
'no-irregular-whitespace': ['error', { // 禁止不规则的空白符,允许在字符串、正则、模板字符串中
skipStrings: true,
skipComments: false,
skipRegExps: true,
skipTemplates: true,
}],
'no-obj-calls': 'error', // 禁止将 Math, JSON, Reflect 作为函数调用
'no-prototype-builtins': 'off', // 允许使用 Object.prototype.builtins (根据项目需求调整)
'no-regex-spaces': 'error', // 禁止正则表达式中出现连续空格
'no-sparse-arrays': 'error', // 禁止数组中出现稀疏项
'no-template-curly-in-string': 'error', // 禁止在普通字符串中使用模板字符串的变量语法
'no-unexpected-multiline': 'error', // 禁止出现意外的多行
'no-unreachable': 'error', // 禁止在 return, throw, break, continue 之后存在代码
'no-unsafe-finally': 'error', // 禁止在 finally 块中使用 return, throw, break, continue
'no-unsafe-negation': 'error', // 禁止对否定进行不安全的操作
'use-isnan': 'error', // 必须使用 isNaN() 而不是 === NaN
'valid-jsdoc': 'off', // JSDoc 注释规范 (根据项目需求调整)
'valid-typeof': 'error', // typeof 比较必须是有效类型
// --- 最佳实践 ---
'accessor-pairs': ['error', { setWithoutGet: true, getWithoutSet: false }], // setter 必须有 getter
'array-callback-return': 'error', // 数组回调函数必须有返回值 (除了 forEach)
'block-scoped-var': 'error', // var 变量应视为块作用域
'class-methods-use-this': 'off', // 允许类方法不使用 this (根据项目需求调整)
'complexity': ['error', { max: 20 }], // 禁止函数复杂度过高
'consistent-return': 'off', // 允许函数在不同分支返回不同类型 (根据项目需求调整)
'curly': ['error', 'multi-line', 'consistent'], // 强制使用大括号,允许单行 if
'default-case': 'off', // 允许 switch 语句没有 default (根据项目需求调整)
'dot-location': ['error', 'property'], // 点号必须在属性前面
'dot-notation': 'off', // 允许使用点表示法访问属性 (根据项目需求调整)
'eqeqeq': ['error', 'always', { null: 'ignore' }], // 必须使用 === 或 !==,允许与 null 比较
'guard-for-in': 'error', // for...in 循环必须有 hasOwnProperty 检查
'no-alert': 'off', // 允许使用 alert (根据项目需求调整)
'no-caller': 'error', // 禁止使用 arguments.caller 和 arguments.callee
'no-case-declarations': 'error', // 禁止在 switch case 中声明变量
'no-div-regex': 'off', // 允许在正则表达式中使用除法操作符 (根据项目需求调整)
'no-else-return': 'off', // 允许 else 中有 return (根据项目需求调整)
'no-empty-function': ['error', { allow: ['functions', 'arrowFunctions'] }], // 禁止空函数,允许用于默认值
'no-empty-pattern': 'error', // 禁止解构空对象或数组
'no-eq-null': 'off', // 允许使用 == null 进行 null 和 undefined 检查 (根据项目需求调整)
'no-eval': 'error', // 禁止使用 eval
'no-extend-native': 'error', // 禁止扩展原生对象
'no-extra-bind': 'error', // 禁止不必要的 bind 调用
'no-extra-label': 'error', // 禁止不必要的 label
'no-fallthrough': 'error', // switch case 必须有 break, return 或 throw
'no-floating-decimal': 'error', // 禁止省略小数点的数字
'no-global-assign': 'error', // 禁止对全局变量赋值
'no-implicit-coercion': ['error', { allow: ['!!'] }], // 禁止隐式类型转换,允许 !!
'no-implicit-globals': 'error', // 禁止在全局作用域定义变量或函数
'no-implied-eval': 'error', // 禁止使用隐式 eval
'no-invalid-this': 'off', // 允许在非类中使用 this (根据项目需求调整)
'no-iterator': 'error', // 禁止使用 __iterator__
'no-labels': 'error', // 禁止使用 label
'no-lone-blocks': 'error', // 禁止孤立的代码块
'no-loop-func': 'error', // 禁止在循环内部定义函数
'no-magic-numbers': 'off', // 允许使用魔术数字 (根据项目需求调整)
'no-multi-spaces': ['error', { // 禁止多余的空格
ignoreEOLComments: true,
exceptions: {
Property: true,
BinaryExpression: false,
VariableDeclarator: true,
ImportDeclaration: true
}
}],
'no-multi-str': 'error', // 禁止字符串换行
'no-new': 'error', // 禁止直接 new 一个类而不赋值
'no-new-func': 'error', // 禁止使用 new Function
'no-new-wrappers': 'error', // 禁止使用 String, Number, Boolean 的构造函数
'no-octal': 'error', // 禁止使用八进制字面量
'no-octal-escape': 'error', // 禁止使用八进制转义符
'no-param-reassign': 'error', // 禁止重新赋值函数参数
'no-proto': 'error', // 禁止使用 __proto__
'no-redeclare': 'error', // 禁止重复声明变量
'no-restricted-properties': 'off', // 禁止使用特定对象属性 (根据项目需求调整)
'no-return-assign': ['error', 'always'], // 禁止在 return 语句中赋值
'no-return-await': 'error', // 禁止在 return 语句中使用 await
'no-script-url': 'error', // 禁止使用 javascript: void(0)
'no-self-assign': 'error', // 禁止自我赋值
'no-self-compare': 'error', // 禁止自我比较
'no-sequences': 'error', // 禁止使用逗号操作符
'no-throw-literal': 'error', // 禁止 throw 字面量,必须是 Error 对象
'no-unmodified-loop-condition': 'error', // 禁止循环条件变量未被修改
'no-unused-expressions': ['error', { // 禁止未使用的表达式
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true
}],
'no-unused-labels': 'error', // 禁止未使用的 label
'no-useless-call': 'error', // 禁止不必要的 call/apply
'no-useless-concat': 'error', // 禁止不必要的字符串连接
'no-useless-escape': 'off', // 允许不必要的转义 (根据项目需求调整)
'no-useless-return': 'off', // 允许不必要的 return (根据项目需求调整)
'no-void': 'error', // 禁止使用 void
'no-warning-comments': 'off', // 允许 TODO/FIXME 注释 (根据项目需求调整)
'no-with': 'error', // 禁止使用 with
'prefer-promise-reject-errors': 'error', // Promise.reject 必须传入 Error 对象
'radix': 'error', // parseInt 必须传入第二个参数
'require-await': 'off', // 允许 async 函数没有 await (根据项目需求调整)
'vars-on-top': 'off', // 允许 var 不在作用域顶层 (根据项目需求调整)
'wrap-iife': ['error', 'inside', { functionPrototypeMethods: true }], // 立即执行函数必须使用括号包裹
// --- 变量 ---
'init-declarations': 'off', // 允许变量先定义后赋值 (根据项目需求调整)
'no-catch-shadow': 'off', // 允许 catch 参数名与变量重名 (根据项目需求调整)
'no-delete-var': 'error', // 禁止使用 delete
'no-label-var': 'error', // 禁止 label 名称与变量重名
'no-restricted-globals': 'off', // 禁止使用特定全局变量 (根据项目需求调整)
'no-shadow': 'off', // 允许变量覆盖上层作用域变量 (根据项目需求调整)
'no-shadow-restricted-names': 'error', // 禁止使用保留字作为变量名
'no-undef': ['error', { typeof: false }], // 禁止使用未定义的变量
'no-undef-init': 'error', // 禁止用 undefined 初始化变量
'no-undefined': 'error', // 禁止重新赋值 undefined
'no-unused-vars': ['error', { // 定义的变量必须使用
vars: 'all',
args: 'none',
caughtErrors: 'none',
ignoreRestSiblings: true
}],
'no-use-before-define': ['error', { // 变量必须先定义后使用
functions: false,
classes: false,
variables: false
}],
// --- Node.js 和 CommonJS ---
'callback-return': 'off', // 允许 callback 不立即 return (根据项目需求调整)
'global-require': 'off', // 允许在非全局作用域 require (根据项目需求调整)
'handle-callback-err': 'error', // callback 中的 error 必须被处理
'no-buffer-constructor': 'error', // 禁止直接使用 Buffer
'no-mixed-requires': 'off', // 允许混合 require (根据项目需求调整)
'no-new-require': 'error', // 禁止 new require()
'no-path-concat': 'error', // 禁止字符串拼接路径
'no-process-env': 'off', // 允许使用 process.env (根据项目需求调整)
'no-process-exit': 'off', // 允许使用 process.exit (根据项目需求调整)
'no-restricted-modules': 'off', // 禁止使用特定模块 (根据项目需求调整)
'no-sync': 'off', // 允许使用同步方法 (根据项目需求调整)
// --- 风格问题 ---
'array-bracket-spacing': ['error', 'never'], // 数组括号内禁止有空格
'block-spacing': ['error', 'always'], // 代码块内允许有空格
'brace-style': 'off', // 大括号风格 (根据项目需求调整)
'camelcase': 'off', // 变量名必须是驼峰式 (根据项目需求调整)
'capitalized-comments': 'off', // 注释首字母大写 (根据项目需求调整)
'comma-dangle': 'off', // 逗号后面是否允许有悬空逗号 (根据项目需求调整)
'comma-spacing': ['error', { before: false, after: true }], // 逗号前后空格
'comma-style': ['error', 'last'], // 逗号风格
'computed-property-spacing': ['error', 'never'], // 计算属性括号内禁止有空格
'consistent-this': 'off', // this 别名 (根据项目需求调整)
'eol-last': 'off', // 文件末尾是否必须有空行 (根据项目需求调整)
'func-call-spacing': ['error', 'never'], // 函数名和括号之间禁止有空格
'func-name-matching': ['error', 'always', { includeCommonJSModuleExports: false }], // 函数名匹配变量名
'func-names': 'off', // 函数名 (根据项目需求调整)
'func-style': 'off', // 函数风格 (根据项目需求调整)
'id-length': 'off', // 变量名长度 (根据项目需求调整)
'indent': ['error', 2, { // 缩进
SwitchCase: 1,
flatTernaryExpressions: true
}],
'jsx-quotes': ['error', 'prefer-double'], // JSX 属性必须使用双引号
'key-spacing': ['error', { beforeColon: false, afterColon: true, mode: 'strict' }], // 键值对冒号前后空格
'keyword-spacing': ['error', { before: true, after: true }], // 关键字前后空格
'line-comment-position': 'off', // 行内注释位置 (根据项目需求调整)
'linebreak-style': 'off', // 行尾符风格 (根据项目需求调整)
'lines-around-comment': 'off', // 注释前后空行 (根据项目需求调整)
'max-depth': ['error', 5], // 最大代码块嵌套深度
'max-len': 'off', // 单行最大长度 (根据项目需求调整)
'max-lines': 'off', // 文件最大行数 (根据项目需求调整)
'max-nested-callbacks': ['error', 3], // 最大回调嵌套深度
'max-params': ['error', 7], // 函数最大参数数量
'max-statements': 'off', // 最大语句数 (根据项目需求调整)
'max-statements-per-line': 'off', // 每行最大语句数 (根据项目需求调整)
'multiline-ternary': 'off', // 三元表达式换行 (根据项目需求调整)
'new-cap': ['error', { newIsCap: true, capIsNew: false, properties: true }], // new 后首字母大写
'new-parens': 'error', // new 后必须有小括号
'newline-per-chained-call': 'off', // 链式调用换行 (根据项目需求调整)
'no-array-constructor': 'error', // 禁止使用 Array 构造函数
'no-bitwise': 'off', // 允许使用位运算 (根据项目需求调整)
'no-continue': 'off', // 允许使用 continue (根据项目需求调整)
'no-inline-comments': 'off', // 允许行内注释 (根据项目需求调整)
'no-lonely-if': 'off', // 允许 else 中只有一个 if (根据项目需求调整)
'no-mixed-operators': 'off', // 允许混合操作符 (根据项目需求调整)
'no-mixed-spaces-and-tabs': 'error', // 禁止混合空格和 tab
'no-multi-assign': 'off', // 允许连续赋值 (根据项目需求调整)
'no-multiple-empty-lines': ['error', { max: 3, maxEOF: 1, maxBOF: 1 }], // 多个空行限制
'no-negated-condition': 'off', // 允许否定条件 (根据项目需求调整)
'no-nested-ternary': 'off', // 允许嵌套三元表达式 (根据项目需求调整)
'no-new-object': 'error', // 禁止使用 Object 构造函数
'no-plusplus': 'off', // 允许使用 ++/-- (根据项目需求调整)
'no-restricted-syntax': 'off', // 禁止特定语法 (根据项目需求调整)
'no-tabs': 'error', // 禁止使用 tab
'no-ternary': 'off', // 允许使用三元表达式 (根据项目需求调整)
'no-trailing-spaces': 'error', // 禁止行尾空格
'no-underscore-dangle': 'off', // 允许变量名以下划线开头 (根据项目需求调整)
'no-unneeded-ternary': 'off', // 允许不必要的 else (根据项目需求调整)
'no-whitespace-before-property': 'error', // 属性前禁止空格
'nonblock-statement-body-position': ['error', 'beside', { overrides: { while: 'below' } }], // 非块语句体位置
'object-curly-newline': ['error', { multiline: true, consistent: true }], // 对象括号换行
'object-curly-spacing': ['error', 'always', { arraysInObjects: true, objectsInObjects: false }], // 对象括号内空格
'object-property-newline': 'off', // 对象属性换行 (根据项目需求调整)
'one-var': ['error', 'never'], // 变量声明模式
'one-var-declaration-per-line': ['error', 'always'], // 变量声明每行一个
'operator-assignment': 'off', // 操作符赋值 (根据项目需求调整)
'operator-linebreak': 'off', // 操作符换行 (根据项目需求调整)
'padded-blocks': 'off', // 代码块填充 (根据项目需求调整)
'padding-line-between-statements': 'off', // 语句间空行 (根据项目需求调整)
'quote-props': 'off', // 对象属性引号 (根据项目需求调整)
'quotes': ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], // 强制单引号
'require-jsdoc': 'off', // 需要 JSDoc (根据项目需求调整)
'semi': ['error', 'always', { omitLastInOneLineBlock: true }], // 结尾必须有分号
'semi-spacing': ['error', { before: false, after: true }], // 分号前后空格
'semi-style': ['error', 'last'], // 分号风格
'sort-keys': 'off', // 对象键排序 (根据项目需求调整)
'sort-vars': 'off', // 变量排序 (根据项目需求调整)
'space-before-blocks': ['error', 'always'], // 代码块前空格
'space-before-function-paren': ['error', { anonymous: 'ignore', named: 'never', asyncArrow: 'always' }], // 函数括号前空格
'space-in-parens': ['error', 'never'], // 括号内空格
'space-infix-ops': 'error', // 操作符间空格
'space-unary-ops': ['error', { words: true, nonwords: false }], // 一元操作符空格
'spaced-comment': ['error', 'always', { block: { exceptions: ['*'], balanced: true } }], // 注释空格
'switch-colon-spacing': ['error', { after: true, before: false }], // switch 冒号空格
'template-tag-spacing': ['error', 'never'], // 模板标签空格
'unicode-bom': ['error', 'never'], // 禁止 BOM
// --- ECMAScript 6 ---
'arrow-body-style': 'off', // 箭头函数体风格 (根据项目需求调整)
'arrow-parens': 'off', // 箭头函数参数括号 (根据项目需求调整)
'arrow-spacing': ['error', { before: true, after: true }], // 箭头函数空格
'constructor-super': 'error', // constructor 必须有 super
'generator-star-spacing': ['error', { before: false, after: true }], // generator 星号空格
'no-class-assign': 'error', // 禁止重新赋值类
'no-confusing-arrow': ['error', { allowParens: true }], // 禁止令人困惑的箭头函数
'no-const-assign': 'error', // 禁止重新赋值 const
'no-dupe-class-members': 'error', // 禁止重复类成员
'no-duplicate-imports': 'error', // 禁止重复导入
'no-new-symbol': 'error', // 禁止 new Symbol
'no-restricted-imports': 'off', // 禁止导入特定模块 (根据项目需求调整)
'no-this-before-super': 'error', // super 调用前禁止使用 this
'no-useless-computed-key': 'error', // 禁止不必要的计算键名
'no-useless-constructor': 'error', // 禁止不必要的 constructor
'no-useless-rename': 'error', // 禁止不必要的重命名
'no-var': 'error', // 禁止使用 var
'object-shorthand': 'off', // 对象字面量简写 (根据项目需求调整)
'prefer-arrow-callback': 'off', // 优先使用箭头函数回调 (根据项目需求调整)
'prefer-const': 'off', // 优先使用 const (根据项目需求调整)
'prefer-destructuring': 'off', // 优先使用解构 (根据项目需求调整)
'prefer-numeric-literals': 'off', // 优先使用数字字面量 (根据项目需求调整)
'prefer-rest-params': 'off', // 优先使用 rest 参数 (根据项目需求调整)
'prefer-spread': 'off', // 优先使用 spread 操作符 (根据项目需求调整)
'prefer-template': 'off', // 优先使用模板字符串 (根据项目需求调整)
'require-yield': 'error', // generator 函数必须有 yield
'rest-spread-spacing': ['error', 'never'], // rest/spread 操作符空格
'sort-imports': 'off', // import 排序 (根据项目需求调整)
'symbol-description': 'error', // Symbol 描述
'template-curly-spacing': ['error', 'never'], // 模板字符串花括号空格
'yield-star-spacing': ['error', 'after'], // yield* 空格
}
};
VS Code 集成 ESLint
在 VS Code 中,安装 ESLint 插件可以提供实时代码检查和错误提示。
在 VS Code 的设置 (settings.json) 中,您可以配置 ESLint 的行为:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true // 保存时自动修复 ESLint 问题
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
]
}
.eslintignore 文件
与 .gitignore 类似,.eslintignore 文件用于指定 ESLint 应该忽略检查的文件或目录。如果没有该文件,您可以创建一个。
# npm 包
/node_modules
package-lock.json
# 构建产物
/dist
/types
# ESLint 缓存
.eslintcache
# 测试覆盖率
/coverage
# 文档
/docs
# Webpack 配置
/scripts
# IDE 配置文件
.idea
# 自动生成的文件
auto-imports.d.ts
components.d.ts
代码检查流程(面试题)
- 配置 (Configuration):设置
.eslintrc文件或package.json中的eslintConfig字段来定义规则集。规则可以继承自预设(如eslint:recommended)或自定义。 - 解析 (Parsing):ESLint 使用解析器(如 Espree)将 JavaScript 代码转换为抽象语法树 (AST),以便理解代码结构。
- 遍历 (Traversing):ESLint 遍历 AST,检查每个节点是否符合定义的规则。
- 报告 (Reporting):ESLint 生成报告,列出所有发现的问题(错误或警告),并根据配置决定是否阻止构建。
- 修复 (Fixing):对于某些规则,ESLint 提供自动修复功能,可以自动修正代码问题。
- 集成 (Integration):ESLint 可集成到 IDE(如 VS Code)提供实时反馈,也可集成到构建工具(如 Webpack)或 CI/CD 流程中,在代码提交前进行检查。
通过这些步骤,ESLint 确保了代码质量和风格的一致性。