玩转ESLint

本文最后更新于:5 个月前

ESLint简介、如何配置使用,各项配置的解释、常见rules的介绍

玩转ESLint

一、前言:ESLint是什么

Lint(Linter) 是一种静态代码分析工具,用于标记代码中某些编码错误、风格问题和不具结构性(易导致 bug)的代码。简单理解就是一个代码检查器,检查目标代码是否符合语法和规定的风格习惯。 ESLint 是基于 ECMAScript/JavaScript 语法的 Lint(StyleLint是CSS语法的Lint),能够:

  • 查出 JavaScript 代码语法问题。
  • 根据配置的规则,标记不符合规范的代码。
  • 自动修复一些结构、风格问题。

二、基本用法

1. 使用介绍

1.1 安装和配置

安装 ESLint 模块

1
2
npm init @eslint/config
# 注意:运行此命令前,目录中必须先存在package.json

交互过程如下图

image-20231008231423207

运行完这条命令之后,会生成一个 eslint的配置文件(例如:.eslintrc),自动安装一些devDependencies

当然,除了使用上述npm init @eslint/config命令的方式进行配置外,你还可以自己手动去创建 eslint 配置文件,并安装对应的依赖。但并不推荐这样做。原因有两个:

(1)eslint配置文件的组成部分较多,对新手不友好,对老手编辑起来也比较麻烦

(2)需要安装对应的开发依赖项,但作为新手,并不清楚需要安装哪些依赖项

1
2
3
4
5
6
7
# 也可以在安装的过程中下载使用指定的共享配置
# npm 6.x
npm init @eslint/config --config semistandard
# ⚠️ npm 7+ 需要使用额外的双杠:
npm init @eslint/config -- --config semistandard
# 或(可以省略 `eslint-config` 前缀)
npm init @eslint/config -- --config eslint-config-semistandard

1.2 CLI运行(了解即可)

这部分了解即可,一般情况要么是使用VSCode插件检查并自动修复,要么是使用pre-commit之类的钩子脚本自动运行lint命令,较少会手动在终端输入命令去进行检查和修复

命令行输入指令即可检查指定文件/目录

1
2
# 在项目根目录输入指令
npx eslint /src/main.js

为了测试检查效果,我在main.js文件中手动制造了一个错误,结果如下:

image-20230616211410204

自动修复

1
npx eslint --fix ./src/main.js
--fix,此项指示 ESLint 尝试修复尽可能多的问题,只有剩余的未修复的问题才会被输出,但不是所有的问题都可以用此项来修复

所以这里并没有发生任何变化,依然输出原来的错误。

1.3 搭配VSCode插件(推荐!)

插件会自动检查项目中是否存在ESLint配置,并在编码过程中进行检查(而不用等到输入命令行输入命令时才执行)

首先,安装 ESLint 插件,安装完自动开启

之后,打开main.js文件,输入一句错误语法的代码,可以看到 ESLint 在此显示了 error 提示

image-20230616212630115

接着,通过VSCode设置(编辑settings.json),实现保存时自动修复

image-20231008230740512

2. 使用须知

  • ESLint能提供的功能包括:语法检查发现问题格式化代码。用户可以根据所需选择ESLint的作用范围。文末附录中,对比了这三种不同工作范围之间的差异。

image-20231008231613506

  • 所有(标准的)第三方规则都使用eslint-config-作为前缀。
  • ESLint默认只匹配所有 JavaScript 文件。如果需要匹配TypeScript文件,需要指定对应的解析器,如@typescript-eslint/parser
    同时ESLint默认·会忽略:(1)node_modules/目录下的文件,(2)所有点文件(.eslintrc.*除外)。想要了解更多【忽略】相关的内容,可以查看忽略文件 - ESLint 中文网 (nodejs.cn)

Q:ESLint作用的范围到底是什么?目录下所有文件?目录下所有js文件?
A:目录下所有js文件

image-20231022235050909

三、配置

1. 配置文件

ESLint 支持多种格式的配置文件:

  • JavaScript - 使用 .eslintrc.js 并导出包含你的配置的对象。
  • JavaScript (ESM) - 在 package.json 中指定 "type":"module" 的 JavaScript 包中运行 ESLint 时使用 .eslintrc.cjs。 请注意,ESLint 目前不支持 ESM 配置。
  • YAML - 使用 .eslintrc.yaml.eslintrc.yml 来定义配置结构。
  • JSON - 使用 .eslintrc.json 定义配置结构。 ESLint 的 JSON 文件也允许 JavaScript 样式的注释。(正常情况下,json文件是不支持注释的)
  • package.json - 在你的 package.json 文件中创建一个 eslintConfig 属性并在那里定义你的配置。

如果同一个目录下有多个配置文件,ESLint 只使用一个。 上述各种文件类型优先级从上到下依次递减

下面分别给出.eslintrcpackage.json中的eslintConfig属性的示例

1
2
3
4
5
6
7
8
// eslintrc.js
module.exports = {
"env": {
"browser": true,
"node": true
},
...
}
1
2
3
4
5
6
7
8
9
10
11
// package.json
{
"name": "mypackage",
"version": "0.0.1",
"eslintConfig": {
"env": {
"browser": true,
"node": true
}
}
}

文件层级关系。当存在多个eslint配置文件,并且位于不同层级的目录中时,

对于被检查文件:

(1)首先在同级目录下寻找eslint配置文件,然后沿着父目录向上寻找eslint配置文件,并合并沿途所有的配置文件;

(2)当同级目录下同时存在 .eslintrc.*和 package.json文件的eslintConfig字段时,前者生效、后者不生效;

(3)向上遍历的过程直到根目录、或者遇到带有root:true的配置时停止;(所以,一般建议声明 root:true 以避免不必要的影响

(4)越靠近被检查文件的配置,优先级越高

2. 配置选项

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
"env": {}, // 环境配置,环境会提供预设的全局变量
"extends": [], // 扩展配置文件,继承另一个配置文件的全部内容
"plugins": [], // 插件配置,用来扩展ESLint,例如完成对Vue或其它语言的检查
"rules": {}, // 规则配置,自定义检查规则,或者禁用指定规则
"globals": {}, // 全局变量配置
"ignorePatterns": [],// 指定ESLint检查时忽略的文件
"parser": "xxx", // 指定解析器,缺省默认为Espree
"parserOptions": {}, // 解析器选项配置,用于指定需要支持的 JavaScript 语言特性
"overrides": [], // 覆盖规则,在同个配置文件下具有最高优先级
}

2.1 env

JavaScript 生态中有多个运行时、版本、扩展和框架。每个所支持的语法和全局变量都不尽相同。环境会提供预设的全局变量(比如brower会提供如window的全局变量),同时设置对应的语法(见es6的例子)。可用的环境请查看:配置语言选项 - ESLint

1
2
3
4
5
6
7
8
// eslintrc.js
module.exports = {
"env": {
"browser": true,
"node": true
},
...
}
  • browser - 浏览器全局变量。
  • node - Node.js 全局变量和 Node.js 作用域。
  • es6 - 启用除模块之外的所有 ECMAScript 6 功能(这会自动将 ecmaVersion 解析器选项设置为 6)。

上面列举了几个常用的env环境,这些环境之间不是互斥的,可以同时定义多个

除了使用「配置文件」的方式,还可以使用「配置注释」的方式指定环境(在最新的ESLint中已经不再支持,所以不建议使用)。如下,在.js文件头部,添加

1
/* eslint-env node, mocha */

这启用了 Node.js 和 Mocha 环境。

2.2 extends

extends 属性值可以是:

  • 一个指定配置的字符串(要么是配置文件的路径,要么是可共享配置的名称,要么是 eslint:recommended,要么是 eslint:all,后两者是随着ESLint模块一起安装的「预定义配置」,所以直接可用)。
  • 一个字符串数组,每个额外的配置都会扩展前面的配置。
1
2
3
4
5
6
module.exports = {
"extends": [ // 注意:这里值是数组类型
"aribnb" // eslint-config-airbnb,前缀可以省略,配置文件需要npm install
],
...
}

更多内容:扩展配置文件 - ESLint

2.3 plugins

你可以用插件以各种不同的方式扩展 ESLint。插件可以包括:

  • 自定义规则
  • 自定义配置
  • 自定义环境
  • 自定义处理器,从其他类型的文件中提取 JavaScript 代码,或在提示前对代码进行预处理

使用插件前,必须下载安装;然后通过plugins属性配置。

1
2
3
4
5
6
{
"plugins": [
"plugin1",
"eslint-plugin-plugin2"
]
}

注:可以省略插件前缀eslint-plugin-,也可以不省略!

不过,插件的各项规则配置都是默认关闭的,所以plugins只是使用插件功能的前提,你必须在rules,extends,env中开启你需要的规则特性

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"plugins":["jest"],

"extends": ["plugin:jest/recommended"],

"env":{
"jest/global":true
},

"rules":{
"jest/valid-expect": "error"
}
}

2.4 rules

rules——规则,是ESLint最核心的组成,用来验证代码是否符合要求,以及不符合要求时如何处理。

对于基本的rule的取值,可以是以下三种之一:

  • "off"0 - 关闭规则
  • "warn"1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error"2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)

但是除了基本的rule之外,还有一些rule还拥有自己的属性,即在控制开关的同时还需要配置属性,如下

1
2
3
4
5
6
7
8
module.exports = {
"rules": {
'quotes': ['error', 'single'],
// quotes表示强制一致使用单引号、双引号、或反引号;第一个选项error表示开启规则并使用error级别
// 第二个选项single表示,强制一致使用单引号
},
...
}

如果是使用来自插件的规则,需要在规则ID前面添加上:插件名称/,eg:

1
2
3
4
5
6
7
8
9
10
11
{
"plugins": [
"plugin1"
],
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["error", "double"],
"plugin1/rule1": "error" //这是来自插件的规则
}
}

image-20231022234145624

2.5 overrides

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"rules": {
"quotes": ["error", "double"]
},

"overrides": [
{
"files": ["bin/*.js", "lib/*.js"],
"excludedFiles": "*.test.js",
"rules": {
"quotes": ["error", "single"]
}
}
]
}

借助 overrides 覆盖属性可以实现更细粒度的控制配置

2.6 ignorePatterns

使用通配符,用来指定在执行linting时要忽略的文件。语法上遵循与.gitignore 相同的规范

【拓展延伸】除了可以在ESLint配置文件中添加ignorepatterns属性外,还可以通过:(1)创建一个.eslintignore文件来指定要忽略的文件;(2)在package.json中使用eslintIgnore属性

1
2
3
4
5
6
7
8
9
10
11
{
"name": "mypackage",
"version": "0.0.1",
"eslintConfig": {
"env": {
"browser": true,
"node": true
}
},
"eslintIgnore": ["hello.js", "world.js"]
}

使用CLI命令时,如果指定了--no-ignore选项,那么(自定义的和默认的)【忽略规则】将不会生效

1
eslint ./config/foo.js --no-ignore

2.7 parser

默认的解析器是Espree,常见的解析器还有:

自定义解析器时,通常还需要结合 parserOptioins 属性进行配置!

1
2
3
4
5
6
"parser": "@typescript-eslint/parser", //babel-parser 会导致ts的类型变量lint失败,故使用@typescript-eslint/parser
"parserOptions": {
"ecmaVersion": 12,
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},

2.8 parserOptions

指定解析器选项(language-options),可用的选项有:

  • ecmaVersion - ECMAScript版本,默认是5,使用latest表示所支持的最新版本,用来指定所支持的语法,如支持ES5、ES6
  • sourceType - 如果你的代码在 ECMAScript 模块中,则设置为 "script"(默认)或 "module"
  • allowReserved - 允许使用保留字作为标识符(如果 ecmaVersion 为 3)
  • ecmaFeatures - 一个对象,指示你要使用哪些附加语言功能:
    • globalReturn - 在全局作用域内允许 return 语句
    • impliedStrict - 启用全局 严格模式(如果 ecmaVersion 为 5 或更大)
    • jsx - 启用 JSX
1
2
3
4
5
6
7
8
9
{
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
}
}

设置解析器选项有助于 ESLint 确定什么是解析错误

3. 规则优先级

如果 extends 配置的是一个数组,那么最终会将所有规则项进行合并,出现冲突的时候,后面的会覆盖前面的;

通过 rules 单独配置的规则优先级比 extends 高;

四、常见的rules

完整的rules列表,请查看:规则 - ESLint 中文文档 (nodejs.cn)

下面列举一些可能会经常用到的规则

rule 说明 推荐配置
comma-dangle 是否允许对象中出现结尾逗号 [“error”, ”only-multiline“]
no-console 不允许出现console语句 2
no-dupe-keys 对象中不允许出现重复的键 2
no-duplicate-case switch语句中不允许出现重复的case标签 2
no-redeclare 不允许变量重复声明 2
camelcase 强制驼峰命名规则 [2, {“properties”: “never”}]
no-inline-comments 不允许行内注释 0
no-mixed-spaces-and-tabs 不允许混用tab和空格 [2, “smart-tabs”]
no-multiple-empty-lines 空行最多不能超过两行 [2, {“max”: 2}]
no-trailing-spaces 一行最后不允许有空格 2
no-var 使用let和const代替var 0

以上都是一些单独的规则,实际上可能很少被直接自己组合这些rule来完成配置,一般都是使用现成的规则,如ESLint内置的eslint:recommendedeslint:all、ESLint标准规则eslint-config-standard(需要下载)、第三方配置eslint-config-airbnb(需要下载)。单独的rule更多时候是用来修正规则集来达到自己的需求。

五、热门开源配置

【说明】:eslint:recommendedeslint:all是随着eslint依赖一并安装的,所以可以在extends属性中直接声明进行扩展。除了这两者之外,其它的第三方配置都需要先下载安装之后,才能使用!

这里列举几个 eslint:recommended里面经典的rule

描述 支持自动修复
array-callback-retrun 在数组方法的回调中强制执行 return 语句 ✔︎
no-dupe-keys 禁止对象字面量中的重复键 ✔︎
no-duplicate-imports 禁止重复模块导入 ✔︎

六、ESLint常用实践

1. 差异化lint

针对不同的文件,使用不同的 lint 规则,使用overrides属性

1
2
3
4
5
6
7
8
9
10
{
"overrides": [
{
"files": ["*-test.js","*.spec.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
}

2. 禁用ESLint检查

规则层面可以细分为:禁用所有的ESLint规则、禁用部分ESLint规则

下面分别演示:

1
/* eslint-disable -- 禁用所有ESLint规则 */
1
/* eslint-disable no-alert, no-console -- 禁用部分ESLint规则 */

禁用范围可以细分为:整个文件禁用、多行禁用、单行禁用

下面分别演示:

1
/* eslint-disable -- 单文件内禁用掉ESLint检查 */
1
2
3
/* eslint-disable */
// 在指定代码行之间禁用ESLint检查
/* eslint-enable */
1
/* eslint-disable-next-line -- 下一行禁用ESLint检查 */

七、附录

ESLint不同功能配置的差异

依赖项的差异

image-20231008233049225

.eslintrc的差异

image-20231008233535403

参考链接

核心概念 - ESLint 中文网 (nodejs.cn)

ESLint 使用教程 - 掘金 (juejin.cn)

ESLint - 基本入门篇 - 掘金 (juejin.cn)

ESLint 入门 - ESLint - 插件化的 JavaScript 代码检查工具

可能需要回头看:Eslint使用入门指南 - 掘金 (juejin.cn)


玩转ESLint
http://timegogo.top/2023/06/17/效率/规范化:玩转ESLint/
作者
丘智聪
发布于
2023年6月17日
更新于
2023年10月22日
许可协议