type
status
date
slug
summary
tags
category
icon
password
这篇文章详细介绍了 ESLint 相关的一些知识,主要分成三大部分:
- ESLint 基本介绍与使用
- ESLint 运行原理与 AST
- 如何编写 ESLint 插件
什么是 ESLint
ESLint 是一个开源的 JavaScript 代码检查工具,由 Nicholas C. Zakas 于2013年6月创建。代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查,一般来说编译程序会内置检查工具。
JavaScript 是一个动态的弱类型语言,在开发中比较容易出错。因为没有编译程序,为了寻找 JavaScript 代码错误通常需要在执行过程中不断调试。ESLint 可以让程序员在编码的过程中发现问题而不是在执行的过程中。
ESLint 的初衷是为了让程序员可以创建自己的检测规则。ESLint 的所有规则都被设计成可插拔的。ESLint 的默认规则与其他的插件并没有什么区别,规则本身和测试可以依赖于同样的模式。为了便于人们使用,ESLint 内置了一些规则,当然,你可以在使用过程中自定义规则。
安装与使用
你可以使用 npm 或者 yarn 安装 ESLint,本文会使用 yarn。首先创建一个目录
eslint-start,初始化package.json文件,然后安装 eslint。安装完成之后需要设置一个配置文件,可以通过命令行工具直接生成:
在这个过程中,ESLint 会让你选择一些选项:
之后会得到一个
.eslintrc.json文件,内容如下:JSON 和 YAML 配置文件是支持注释的,ESLint 会 ignore 配置文件中的注释
现在你可以在任何文件或目录上运行 ESLint。
例子
下面来看一个简单的例子,首先添加一条规则到
.eslintrc.json中的rules部分:"prefer-const": "error",这条规则要求声明后没有被重新赋值的变量必须使用const,否则会报错。ESLint 官方提供的所有规则都可以在这个页面找到:https://eslint.org/docs/rules/
之后在项目根目录创建一个
index.js文件,并把以下内容写入到文件中:接下来就可以运行 ESLint 了:
命令执行完之后,会在控制台看到以下错误:

也可以通过在上面命令的基础上添加
--fix,这样 ESLint 会尝试去修复错误,对于上图中的错误,ESLint 会自动把let替换为const,感兴趣的读者可以自行尝试。rules
ESLint 中有两个重要的部分:rules 和 plugins。
在上一个例子中,我们使用了键值对的形式来添加一个规则,键是规则的名称,值是错误级别,这一类的规则是没有属性的,只需要开启或者关闭。
Rule 的错误级别可以是以下值之一:
off或者0:关闭规则
warn或者1:开启规则,使用警告级别的错误
error或者2:开启规则,使用错误级别的错误
除了键值对形式的规则外,还有一部分规则除了需要开启或关闭,还需要配置属性。
plugins
尽管 ESLint 附带了一些很好的规则,但通常它们不足以满足项目的所有需求,特别是如果使用 React、Vue、Angular 等库和框架进行构建时。ESLint 插件允许我们根据项目的需要添加自定义规则。插件作为 npm 模块发布,命名格式为
eslint-plugin-<plugin-name>。要使用插件,首先需要通过 npm 安装插件,然后把插件添加到
eslintrc配置文件中的plugins中。例如,你想使用一个名为eslint-plugin-my-awesome-plugin的插件,你可以像这样把它添加到你的配置文件中:需要注意的是,添加了这个插件不意味着这个插件的所有规则都会被自动启用,仍然需要单独应用要与该插件一起使用的每个规则,在配置文件中的 rules 对象上配置。
但是如果每一个规则都需要配置一遍,对开发者来说很不友好,所以 ESLint 提供了另一种方式:可共享的配置。
可共享的配置
ESLint 允许我们通过将配置发布到 npm 来共享配置。与插件的名字类似,可共享的配置以
eslint-config-<config-name>的格式发布。要使用可共享配置,首先也要从 npm 安装,然后可以通过
extends部分来扩展项目的 ESLint 配置。我们可以通过将多个配置添加到数组中来扩展它们,如果配置修改相同的规则,则前面的配置的规则将被后面的配置覆盖,因此在这些情况下顺序很重要。
需要注意的是,可共享配置不仅仅用于共享规则集,它们可以是具有自己的插件、格式化程序等的完整配置,甚至还可以从其他配置扩展。
带有配置的插件
除了使用
eslint-config-<config-name>来发布可共享配置之外,插件本身也可以附带不同的可共享的配置集,我们可以根据项目需要来选择使用哪一个。如果你以前有配置过 ESLint,很可能见过这样的写法:我们可以通过
plugin:前缀使用插件附带的这些配置。例如,我们正在使用一个名为eslint-plugin-my-awesome-plugin的插件,它带有一个名为recommended的配置。然后,我们可以将plugin:my-awesome-plugin/recommended添加到配置中的extends部分,来从该可共享配置扩展。我们甚至不需要在
eslintrc配置文件中把prettier添加到plugins中,因为recommended配置中已经包含了。我们以eslint-plugin-prettier为例,如果查看代码,就会发现这个插件导出了一个recommended配置,内容如下:通过
"extends": "eslint:recommended",所有在 rules 页面打钩✔️的 rules 都会被开启。ESLint 工作原理
了解了 ESLint 基本的使用之后,我们再来了解一下 ESLint 的工作原理,也为接下来的编写 ESLint 插件部分做准备。
在 ESLint 中,默认使用 Espree 来解析 JavaScript,将代码转换成 AST(抽象语法树),然后去拦截检测是否符合我们规定的书写方式,最后让其展示报错、警告或正常通过。
ESLint 的核心就是一系列 rules,而 rules 的核心就是利用 AST 来做校验。在 ESLint 中,一切都是可插拔的,每条规则相互独立。
架构

这张图是 ESLint 官网给出的一个架构图。
bin/eslint.js- 这个是命令行应用程序实际上执行的文件,它仅仅是个封装,用来启动 ESLint,并向cli传递命令行参数。
lib/api.js- 这个是require("eslint")的入口,导出了一个包含Linter、ESLint、RuleTester和SourceCode的对象。
lib/cli.js- 这个是 ESLint CLI 的核心。它接受一个参数数组,然后使用eslint执行命令。通过保持这个文件作为一个单独的应用程序,它允许其他人在另外的 Node.js 程序中有效的调用 ESLint,就好像是在命令行上操作的一样。它最重要的函数是cli.execute()。它也扮演着读取文件、遍历目录,输入和输出的角色。
lib/cli-engine/:这个模块是CLIEngine类,它查找源代码文件和配置文件,然后使用Linter类进行代码验证。这里面包括了配置文件、解析器、插件和格式化程序的加载逻辑。
lib/linter/- 这个模块是基于配置选项进行代码验证的核心Linter类。这个文件不与控制台交互,没有 I/O。对于其他需要验证 JavaScript 文本的 Node.js 程序,他们将能够直接使用此接口。
lib/rule-tester/- 这个模块是RuleTester类,它是 Mocha 的包装器,因此可以对规则进行单元测试。这个类让我们可以为每个已实现的规则编写格式一致的测试,并确信每个规则都有效。 RuleTester 接口以 Mocha 为模型,与 Mocha 的全局测试方法一起使用。 RuleTester 也可以修改为与其他测试框架一起使用。
lib/source-code/- 这个模块是SourceCode类,用于表示解析后的源代码。它接收源代码和代表代码的 AST 节点。
lib/rules- 包含了内置规则
AST
如果想要深入了解 ESLint 的工作原理,那么 AST 毫无疑问是极其重要的一部分。AST 是源代码语法结构的一种抽象表示,它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码的一种结构。
AST如何生成
JavaScript 执行的第一步是读取文件中的字符流,然后通过词法分析生成 token,之后再通过语法分析( Parser )生成 AST,最后生成机器码执行。
整个解析过程主要分为以下两个步骤:
- 分词:将整个代码字符串分割成最小语法单元数组
- 语法分析:在分词基础上建立分析语法单元之间的关系
词法分析
词法分析,也称之为扫描(scanner),简单来说就是调用
next() 方法,一个一个字母的来读取字符,然后与定义好的 JavaScript 关键字符做比较,生成对应的 Token。Token 是一个不可分割的最小单元:例如
var这三个字符,它只能作为一个整体,语义上不能再被分解,因此它是一个 Token。词法分析器里,每个关键字是一个 Token ,每个标识符是一个 Token,每个操作符是一个 Token,每个标点符号也都是一个 Token。除此之外,还会过滤掉源程序中的注释和空白字符(换行符、空格、制表符等。
最终,整个代码将被分割进一个 tokens 列表(或者说一维数组)。
语法分析
语法分析会将词法分析出来的 Token 转化成有语法含义的抽象语法树结构。同时,验证语法,语法如果有错的话,抛出语法错误。
AST Explorer 是一个工具网站,它能查看代码被解析成 AST 的样子。

编写 ESLint 插件
介绍了原理之后,接下来就是我们的实战部分了。有些时候,已有的 Lint 规则并不能满足项目需求,我们可以根据需求创建自己的规则。
接下来我们以一个简单的需求为例,开发一个属于我们自己的 ESLint 插件。
需求:使用
const声明基本类型的变量时,变量名不能出现小写字母。初始化项目
想要创建一个 ESLint rule,首先需要创建一个 ESLint 插件。我们在 plugins 部分有提到过,插件是一个以
eslint-plugin开头的 npm 模块,这是 ESLint 官方规定的。首先初始化
package.json,内容如下:创建规则
之后在根目录创建一个
index.js文件,用来存放 rule 的具体逻辑。其实到这里一个基本的插件我们就创建完成了,只包含两个文件:
package.json和index.js。这个插件只提供了一个规则:constant-capitalization。下面来详细介绍一下 rule 部分的具体内容。插件中的每个规则都必须包含两条属性:
meta和create。meta:元数据,包含了规则的通用信息,比如规则的类型,以及一些用来用来描述规则的信息。
create:一个函数,它将逐个节点访问整个代码的语法树,并让我们对节点进行操作。参数context包含与规则上下文相关的信息,这个函数返回一个对象,对象的属性是 AST 中的选择器,ESLint 会收集这些选择器,在 AST 遍历过程中会执行所有监听该选择器的回调。
回到我们的规则本身,为了找到符合条件的节点,我们需要观察代码解析成 AST 的结果,下面的截图是在 AST Explorer 中输入
const foo = '123';得到的 AST:
通过观察 AST 可以发现通过
node.parent.kind === 'const' && hasLowerCase(node.id.name) && node.init.type === 'Literal'就可以过滤出符合条件的节点。对于符合条件的节点,调用context.report来发布警告或错误(取决于你所使用的配置)。该方法只接收一个参数,是个对象。测试
了解了规则的实现后,让我们通过一个实际的例子,来测试一下我们编写的规则。
首先在当前插件的根目录执行
yarn link,你会看到下面类似的输出。
测试项目我们可以继续使用在安装与使用章节创建的项目,首先运行
yarn link "eslint-plugin-awesome-rules",把这个模块链接到我们编写的的本地插件。之后运行yarn add eslint-plugin-awesome-rules@link:1.0.0把插件添加到package.json中。我们在前面的 plugins 部分提到过,安装好插件之后,还需要在 ESLint 的配置文件中进行配置。配置好的
.eslintrc.json文件长这样:之后我们把
index.js文件中的内容改成下面的内容:运行命令:
yarn run eslint index.js,就会在控制台看到我们期望的输出:
至此,一个最简单的 ESLint 插件就创建完成了。
使用 Yeoman generator
上面我们通过手动创建项目来编写了一个插件,是为了让示例尽量精简,只专注在规则本身。但是如果我们想把编写的插件发布到 npm,更推荐大家使用 Yeoman generator。
Yeoman generator 是 ESLint 官方为我们开发 eslint 插件提供的脚手架,用于生成包含指定框架结构的工程化目录结构。
首先全局安装
yo和generator-eslint:创建项目目录,使用命令行初始化项目:
命令行会要求你输入一些插件相关的信息,之后会生成一些必要的文件。
如果要创建一个自定义规则,还需要键入下面这个命令,来添加一些创建 rule 相关的文件。
最终的文件结构长这样:

lib/rules/constant-capitalization.js文件的内容长这样(删掉了不必要的注释):可以发现,和我们手动创建插件的文件内容很像,这个文件就是我们编写 rule 逻辑代码的地方。
使用
yo eslint:rule创建规则时,在docs和tests/lib文件夹中各有一个和 rule 同名的文件,这是我们写规则文档和测试的地方,如果我们要发布到 npm,文档和完整的测试还是很有必要的。总结
本篇文章到这里就结束了,我们一步步由浅入深,介绍了 ESLint 的基本使用、工作原理、AST以及如何编写一个插件等,希望这篇文章给你带来了一些收货,让你对 ESLint 有了一个更深入的了解!
- Author:大胖猫
- URL:http://preview.tangly1024.com/article/223f4632-e87d-804d-9f99-e4d431f702b3
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
.png?table=block&id=223f4632-e87d-804d-9f99-e4d431f702b3&t=223f4632-e87d-804d-9f99-e4d431f702b3)









