# eslint

ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。与 JSLint、JSHint 不同的是:

  • ESLint 使用 Espree 解析 JavaScript。
  • ESLint 使用 AST 去分析代码中的模式。
  • ESLint 是完全插件化的。每一个规则都是一个插件并且你可以在运行时添加更多的规则。

# 基础使用

安装:

yarn add -D eslint

生成配置文件:

./node_modules/.bin/eslint --init

你也可以全局安装,这样可以方便使用 eslint 命令:

yarn global add eslint
eslint --init

demo.js 文件进行校验:

eslint demo.js

对于一个项目而言,通常会将其安装到局部(使用的任何插件或可共享配置都必须安装在本地),为了方便使用我们可以在 package.json 文件中配置相应的命令:

{
  "script": {
    "eslint": "eslint demo.js"
  }
}

现在通过 npm run eslint 命令也可以对指定的文件进行校验。

# 配置

ESlint 被设计为完全可配置的,这意味着你可以关闭每一个规则而只运行基本语法验证,或混合和匹配 ESLint 默认绑定的规则和你的自定义规则。有两种主要的方式来配置 ESLint:

配置注释 - 使用 JavaScript 注释将配置信息直接嵌入到文件中。譬如:

// 指定环境
/* eslint-env node, mocha */

// 指定全局变量
/* global var1, var2:writable */

// 配置规则
/* eslint quotes: ["error", "double"], curly: 2, "plugin1/rule1": "error" */

// 关闭/开启 检查,支持指定特定的规则
/* eslint-disable */
// Business code...
/* eslint-enable */

// 关闭对 当前行/下一行 的检查,支持指定特定的规则
/* eslint-disable-line */
/* eslint-disable-next-line */

配置文件 - 使用任一的文件(.eslintrc.js、.eslintrc.yaml、.eslintrc.yml、.eslintrc.json、.eslintrc 或在 package.json 文件中创建 eslintConfig 属性)来为全部的目录和它的子目录指定配置信息。

其实,通过命令行也可以传递一些配置项,具体的优先级唯配置注释最高,命令行参数次之,项目级配置文件紧随其后。如果你在你的主目录(通常 ~/)有一个配置文件,ESLint 只有在无法找到其他配置文件时才使用它。

# 配置项

在配置文件中有很多信息可以配置:

  • Environments - 指定脚本的运行环境。每种环境都有一组特定的预定义全局变量。
  • Globals - 脚本在执行期间访问的额外的全局变量。
  • Rules - 启用的规则及其各自的错误级别。

所有这些选项让你可以细粒度地控制 ESLint 如何对待你的代码。

# Parser

ESLint 默认使用 Espree (opens new window) 作为其解析器,你可以在配置文件中指定一个不同的解析器,只要该解析器符合下列要求:

以下解析器与 ESLint 兼容:

你可以在你的 .eslintrc 文件里通过 parser 选项指定要使用的解析器:

{
  "parser": "babel-eslint"
}

# Parser Options

指定解析器参数。为了让 ESLint 在处理非 ECMAScript 5 特性时正常工作,配置属性 parserOptions 仍然是必须的。

{
  "parserOption": {
    // 指定要使用的 ECMAScript 版本,可以使用 6、7、8、9 或 10,默认值 5
    "ecmaVersion": 5,
    // 设置为 script(默认)或 module(如果你的代码是 ECMAScript 模块)
    "sourceType": "script",
    // 指定你想使用的额外的语言特性,所有选项默认都是 false
    "ecmafeatures": {
      // 允许在全局作用域下使用 return 语句
      "globalReturn": false,
      // 启用全局 strict 模式(严格模式)
      "impliedStrict": false,
      // 启用 JSX
      "jsx": false,
      // 启用对实验性功能的支持,详细可参考官网
      "experimentalObjectRestSpread": false
    }
  }
}

注意:使用 { "parserOptions": { "ecmaVersion": 6 } } 会开启对 ES6 语法的支持,但是对于并不意味着同时支持新的 ES6 全局变量或类型。

# Processor

处理器可以从另一种文件中提取 JavaScript 代码,然后让 ESLint 检测 JavaScript 代码。或者处理器可以在预处理中转换 JavaScript 代码。

若要在配置文件中指定处理器,请使用 processor 键,并使用由插件名和处理器名组成的串接字符串加上斜杠。例如,下面的选项启用插件 a-plugin 提供的处理器 a-processor

{
  "plugins": ["a-plugin"],
  "processor": "a-plugin/a-processor"
}

要为特定类型的文件指定处理器,可以用 overrides 键和 processor 键的组合。例如,下面对 *.md 文件使用处理器 a-plugin/markdown

{
  "plugins": ["a-plugin"],
  "overrides": [
    {
      "files": ["*.md"],
      "processor": "a-plugin/markdown"
    }
  ]
}

处理器可以生成命名的代码块,如 0.js1.js。ESLint 将这样的命名代码块作为原始文件的子文件处理。你可以在配置的 overrides 部分为已命名的代码块指定附加配置。

例如,下面的命令对以 .js 结尾的 markdown 文件中的已命名代码块禁用 strict 规则:

{
  "plugins": ["a-plugin"],
  "overrides": [
    {
      "files": ["*.md"],
      "processor": "a-plugin/markdown"
    },
    {
      "files": ["**/*.md/*.js"],
      "rules": {
        "strict": "off"
      }
    }
  ]
}

ESLint 检查指定代码块的文件扩展名,如果 --ext CLI option 不包含文件扩展名,则忽略这些扩展名。如果您想要删除除 *.js 之外的已命名代码块,请确保指定 --ext 选项。

# Environments

每个环境定义了一组预定义的全局变量。可用的环境包括但不仅是:

  • browser - 浏览器环境中的全局变量。
  • node - Node.js 全局变量和 Node.js 作用域。
  • commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。
  • shared-node-browser - Node.js 和 Browser 通用全局变量。
  • es6 - 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
  • jquery - jQuery 全局变量。
  • jest - Jest 全局变量。
  • amd - 将 require()define() 定义为像 amd (opens new window) 一样的全局变量。
  • mocha - 添加所有的 Mocha 测试全局变量。

各个环境之间并不是互斥的,所以你可以同时定义多个:

{
  "env": {
    "browser": true,
    "node": true
  }
}

如果你想在一个特定的插件中使用一种环境,确保提前在 plugins 数组里指定了插件名,然后在 env 配置中不带前缀的插件名后跟一个 /,紧随着环境名。例如:

{
  "plugins": ["example"],
  "env": {
    "example/custom": true
  }
}

# Globals

当访问当前源文件内未定义的变量时,no-undef 规则将发出警告。如果你想在一个源文件里使用全局变量,推荐你在 ESLint 中定义这些全局变量,这样 ESLint 就不会发出警告了。

要在配置文件中配置全局变量,需要把 globals 设置为一个对象,该对象包含以你希望使用的每个全局变量。对于每个全局变量键,将对应的值设置为 "writable" 以允许重写变量,或 "readonly" 不允许重写变量。例如:

{
  "globals": {
    "var1": "writable",
    "var2": "readonly"
  }
}

可以使用字符串 "off" 禁用全局变量。例如,在大多数 ES2015 全局变量可用但 Promise 不可用的环境中,你可以使用以下配置:

{
  "env": {
    "es6": true
  },
  "globals": {
    "Promise": "off"
  }
}

# Rules

在配置文件中,我们可以通过 rules 字段来配置特定的规则,该字段的值是一个对象,每个 key 都是一个规则的名称,对应的 value 则是一个数组。

数组中的第一个值是错误级别,它可以是:

  • "off" or 0 - 关闭规则
  • "warn" or 1 - 将规则视为一个警告(不会影响退出码)
  • "error" or 2 - 将规则视为一个错误 (当被触发的时候,程序会以 1 为错误码退出)

同时,针对某些可配置的规则,你可以通过数组的第二项来传递一些选项。

{
  "rules": {
    "eqeqeq": "off",
    "curly": 2,
    "quotes": ["error", "double"],
    "plugin1/rule1": "error"
  }
}

在这些配置文件中,规则 plugin1/rule1 表示来自插件 plugin1rule1 规则。

注意:当指定来自插件的规则时,确保删除 eslint-plugin- 前缀。ESLint 在内部只使用没有前缀的名称去定位规则。

# Plugins

ESLint 支持使用第三方插件。在使用插件之前,你必须使用 npm (opens new window) 安装它。

插件除了可以有 Processor 外,还主要用于提供了除预设之外的自定义规则,当你在 ESLint 的规则里找不到你需要的时就可以借用插件来实现。

在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。

{
  "plugins": ["plugin1", "eslint-plugin-plugin2"]
}

注意:插件是相对于 ESLint 进程的当前工作目录解析的。换句话说,ESLint 将加载与用户通过从项目 Node 交互解释器运行 ('eslint-plugin-pluginname') 获得的相同的插件。

# Overrides

若要禁用一组文件的配置文件中的规则,请使用 overridesfiles。例如:

{
  "rules": {},
  "overrides": [
    {
      "files": ["*-test.js", "*.spec.js"],
      "rules": {
        "no-unused-expressions": "off"
      }
    }
  ]
}

# Shared Settings

ESLint 支持在配置文件添加共享设置。你可以添加 settings 对象到配置文件,它将提供给每一个将被执行的规则。如果你想添加的自定义规则而且使它们可以访问到相同的信息,这将会很有用,并且很容易配置。

在 JSON 中:

{
  "settings": {
    "sharedData": "Hello"
  }
}

# Extends

每个配置文件可以被基础配置中的已启用的规则继承,其关键的 extends 字段可以是:

  • 指定配置的字符串(配置文件的路径、可共享配置的名称、eslint:recommended 或 eslint:all)。
  • 字符串数组:每个配置继承它前面的配置。

ESLint 递归地扩展配置,因此基本配置也可以具有 extends 属性。extends 属性中的相对路径和可共享配置名从配置文件中出现的位置解析。

rules 属性可以做下面的任何事情以扩展(或覆盖)规则:

  • 启用额外的规则。
  • 改变继承的规则级别而不改变它的选项:
    • 基础配置:"eqeqeq": ["error", "allow-null"]
    • 派生的配置:"eqeqeq": "warn"
    • 最后生成的配置:"eqeqeq": ["warn", "allow-null"]
  • 覆盖基础配置中的规则的选项:
    • 基础配置:"quotes": ["error", "single", "avoid-escape"]
    • 派生的配置:"quotes": ["error", "single"]
    • 最后生成的配置:"quotes": ["error", "single"]

通常会使用 extends 继承共享的配置 (opens new window)和插件提供的配置configs_in_plugins (opens new window)

# 其它

设置配置文件:

你可以通过命令行提供的 -c 选项来指定使用哪个配置文件。

层叠配置:

默认情况下,ESLint 会在所有父级目录里寻找配置文件,一直到根目录。

层叠配置意味着当你在多层目录中都拥有配置文件时,ESLint 将会使用离要检测的文件最近的 .eslintrc 文件作为最高优先级(是覆盖,而不是直接代替),然后才是父目录里的配置文件,等等。

ESLint 一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找。

在 ESLint 中还支持一些基于 Glob Pattern (opens new window) 的配置,以便于做一些要更精细的配置。

# 忽略文件或目录

有时候,你并不想对项目下的所有文件做校验,尤其是像 node_modules 这样的目录。此时,你可以通过在项目根目录创建一个 .eslintignore 文件告诉 ESLint 去忽略特定的文件和目录。

.eslintignore 文件是一个纯文本文件,其中的每一行都是一个 glob 模式表明哪些路径应该忽略检测。Globs 匹配使用 node-ignore,所以大量可用的特性有:

  • # 开头的行被当作注释,不影响忽略模式。
  • 路径是相对于 .eslintignore 的位置或当前工作目录。
  • 忽略模式同 .gitignore 规范
  • ! 开头的行是否定模式,它将会重新包含一个之前被忽略的模式。
  • 忽略模式依照 .gitignore 规范.

除了 .eslintignore 文件中的模式,ESLint 总是忽略 /node_modules/*/bower_components/* 中的文件。

你也可以使用命令行 --ignore-path 选项来指定忽略规则文件所在位置。

# 配置案例

接下来我们使用 Airbnb (opens new window) 提供的校验规则为例,列举几种配置情况。

# 基础的 JavaScript 校验

主要由 eslint-config-airbnb-base 包来进行校验,通过下面的命令查看此包的依赖并进行安装:

npm info "eslint-config-airbnb-base@latest" peerDependencies

然后在配置文件中进行继承:

{
  "extends": "airbnb-base/legacy"
}

# 校验 React 项目

主要由 eslint-config-airbnb 包来进行校验,通过下面的命令查看此包的依赖并进行安装:

npm info "eslint-config-airbnb@latest" peerDependencies

然后在配置文件中进行继承:

{
  "extends": "airbnb"
}

# 基础的 TypeScript 校验

安装依赖:

yarn add -D eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin

配置:

module.exports = {
  root: true,
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
}

在进行校验时不要忘了使用 --ext 选项来指定校验文件的扩展名:

yarn eslint . --ext .js,.jsx,.ts,.tsx

更多使用方式可以点击查看更多 (opens new window)

# 参考