ESLint 配置详解

247 阅读8分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

前言

ESlint 被设计为完全可配置的,这意味着你可以关闭每一个规则而只运行基本语法验证,或混合和匹配 ESLint 默认绑定的规则和你的自定义规则,以让 ESLint 更适合你的项目。

本文我们来探讨ESLint的配置详情。

ESLint的配置文件,通常在项目根目录下.eslintrc相关文件中。

module.exports = {
    "root": true,
    "globals": {
    },
    "env": {
    },
    "extends": [
    ],
    "parser": "",
    "parserOptions": {
    },
    "plugins": [
    ],
    "rules": {
    }
}

root

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

root的属性值变为true后,会停止在父级目录中查找配置文件。

globals

在我们常见的ESLint的各种规范中,都不允许使用未在代码中声明的变量。但开发中会经常用到一些自带的全局变量。

  • 浏览器中的 windowdocumentconsole
  • node环境中的__dirname
  • Jquery中的全局变量
  • Jest中的全局变量
  • 代码中自定义的全局变量
  • ......

那怎么办呢?其实ESLint也帮我们考虑到了这种情况,我们需要设置globals参数去告诉ESLint,我项目中有哪些全局变量。

module.exports = {
  // 配置上 globals 把 $、_ 定义为全局变量
  globals: {
    "$": "readonly", // 可以读取,不能修改
    "_": "writable",   // 可以读取,可以修改
  }
};

如上所示,我们将$_定义为全局变量,后面参数控制全局变量是否可以修改,readonly等价于true

  • readonly/false —— 只读
  • writable/true —— 可写
  • off —— 禁用该全局变量
  • 说明:true/false 等价于只读/可写,但不推荐使用。详见ESLint官网

注意:要启用no-global-assign规则来禁止对只读的全局变量进行修改。

那么问题来了,诸如浏览器和node环境中大量的全局变量,我们也要挨个去配置么?

其实不用的,ESLint帮我们考虑到了这层,我们只需要设置env字段即可。

env

envESLint中表示环境,一个环境定义了一组预定义的变量,以便我们在相应环境开发。

可用的环境包括:

  • browser - 浏览器环境中的全局变量。
  • node - Node.js 全局变量和 Node.js 作用域。
  • commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。
  • shared-node-browser - Node.js 和 Browser 通用全局变量。
  • es6 - 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
  • worker - Web Workers 全局变量。
  • amd - 将 require() 和 define() 定义为像 amd 一样的全局变量。
  • mocha - 添加所有的 Mocha 测试全局变量。
  • jasmine - 添加所有的 Jasmine 版本 1.3 和 2.0 的测试全局变量。
  • jest - Jest 全局变量。
  • phantomjs - PhantomJS 全局变量。
  • protractor - Protractor 全局变量。
  • qunit - QUnit 全局变量。
  • jquery - jQuery 全局变量。
  • prototypejs - Prototype.js 全局变量。
  • shelljs - ShellJS 全局变量。
  • meteor - Meteor 全局变量。
  • mongo - MongoDB 全局变量。
  • applescript - AppleScript 全局变量。
  • nashorn - Java 8 Nashorn 全局变量。
  • serviceworker - Service Worker 全局变量。
  • atomtest - Atom 测试全局变量。
  • embertest - Ember 测试全局变量。
  • webextensions - WebExtensions 全局变量。
  • greasemonkey - GreaseMonkey 全局变量。

这些环境并不是互斥的,所以你可以同时定义多个。

module.exports = {
    "env": {
        "browser": true,
        "node": true
    },
}

以上所示就启用了 浏览器Node.js 的环境。此时再使用相关的全局变量,就不会报错未定义了。

ESLintenv的实现也是借助了globals,有兴趣可参考 env的具体实现

rules

rules顾名思义,就是ESLint所校验的规则。

ESLint本身附带了大量的规则ESLint自带规则

ESlint规则的设置遵循如下原则:

  • "off" 或 0 - 关闭规则
  • "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
  • 规则只有一个值时,使用字符串。需要传递额外参数的时候,使用数组,数组内后续内容会以参数的形式传入
module.exports = {
    "rules": { 
        "no-console": 'warn', // console 报警 
        "quotes": ['error', 'single'] // 引号必须单引号 
    } 
}

以上定义了两条规则

  • 代码中出现console的时候warning
  • 引号规则中,将第二位single作为参数传入,整体代表引号是双引号的时候error

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

  • 启用额外的规则

  • 改变继承的规则级别而不改变它的选项:

    • 基础配置:"eqeqeq": ["error", "allow-null"]
    • 派生的配置:"eqeqeq": "warn"
    • 最后生成的配置:"eqeqeq": ["warn", "allow-null"]
  • 覆盖基础配置中的规则的选项

    • 基础配置:"quotes": ["error", "single", "avoid-escape"]
    • 派生的配置:"quotes": ["error", "single"]
    • 最后生成的配置:"quotes": ["error", "single"]

plugins

虽然ESlint有了大量的内部规则,但我们开发中可能会遇到这些规则覆盖不了的情况,那怎么办呢?

ESLint 支持使用第三方插件。在使用插件之前,你必须使用 npm 安装它。常见的有:

  • eslint-config-airbnb
  • eslint-config-react
  • ......

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

module.exports = {
  "plugins": [
      "vue"
  ]
}

上述就是针对vue所开发的第三方插件,完整的名称是eslint-plugin-vue,里面针对vue的特定场景开发了一些规则。

需要注意的是,plugins仅仅只是加载了插件,并不代表着启用相关的规则。

启用插件需要在rules中明确,或者使用extends

你可以理解为,plugin只是定义了一些函数的实现方法,具体的调用还是需要在rulesextends

extends

虽然我们要按照不同的需求、风格、项目去配置不同的规则,但项目中的很多规则都是大同小异的,如果每个项目都需要将繁琐的各种规则去配置一遍,那就显得有点不近人情了。这时候就需要用到extends

extends顾名思义,继承,就是将别人整理好的规则继承下来,直接用到自己的项目当中。它所继承的东西,就是一份别人已经配置好的.eslintrc.js文件。

extends 属性值可以是到基本配置文件的绝对路径,也可以是相对路径。ESLint 解析一个相对于使用它的配置文件的基本配置文件的相对路径。

extends 属性值可以省略包名的前缀 eslint-config-

大致可分为三类:

  • ESLint内置规则包
  • 第三方规范包
  • 第三方插件中的规范包

ESLint内置规则包

内置规则包指的是跟随ESLint一同下载好的规则包:

  • eslint:recommended 仅使用ESLint推荐的规则
  • eslint:all 使用ESLint内置的所有规则

具体规则内容可查看ESLint内置规则

ESLint官方提示: 这些配置 不推荐在产品中使用,因为它随着 ESLint 版本进行更改。使用的话,请自己承担风险

module.exports = {
    "extends": [
        "eslint:recommended",
    ]
}

第三方规范包

第三方规范包指的是广大人民群众贡献的规范包,常见的有:

  • eslint-config-airbnb
  • eslint-config-react
  • ......

extends 属性值可以省略包名的前缀 eslint-config-

module.exports = {
    "extends": [
        "airbnb",
    ]
}

第三方插件中的规范包

这里对应的是plugin中已引入的包。 此类extends 属性值由以下组成

  • plugin:
  • 包名 (省略了前缀,比如,vue)
  • /
  • 配置名称 (比如 base)

eslint-plugin-vue为例,我们需要先在plugins中引入,然后再继承具体的规则。比如:plugin:vue/base

module.exports = {
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    "extends": [
        "plugin:vue/base",
    ]
}

parser

解析器,ESLint会通过解析器将我们写的代码转化成ESTree(AST的一种),ESLint会对ESTree进行校验

Espree

ESLint 默认的 parser ,只转换 js,默认支持 ES5 的语法,可以通过制定 parserOptions 给 Espree 传递如下选项。

"parserOptions": {
   "ecmaVersion": 6,
   "sourceType": "module",
   "ecmaFeatures": {
      "jsx": true
    }
}
  • ecmaVersion 可以开启更高 ES 版本的校验(已加入ES标准的语法,不包括实验性的语法),但需要注意的是一些新标准中的语法对 ESLint 的版本也有要求,如果发现ESLint 不支持校验,可能需要升级 ESLint 版本
  • sourceType 可以设置为 "script",如果使用 ESModule 可以设置为 "module"

@babel/eslint-parser

parser 允许你使用 ESLint 校验所有 babel code。

ESLint默认解析器核心规则仅支持最新的最终 ECMAScript 标准,不支持 Babel 提供的实验性(例如新功能)和非标准(例如FlowTypeScript类型)语法。

@babel/eslint-parser 是允许 ESLint 在由 Babel 转换的源代码上运行的解析器。

当你使用 babel 时,babel 的解析器会把你的 code 转换为 AST,该解析器会将其转换为 ESLint 能懂的 ESTree

praserparserOptions 默认配置如下:

module.exports = {
  parser: "@babel/eslint-parser",
  parserOptions: {
    requireConfigFile: true, // 是否需要 babel 配置文件
    sourceType: "module", // script 或者 module
    allowImportExportEverywhere: false, // 设置为 true,import 和 export 声明 可以出现在文件的任务位置,否则只能出现在顶部
    ecmaFeatures: {
      globalReturn: false, // 设置为 true,当 sourceType 为 script 时,允许全局 return
    },
    babelOptions: {
      configFile: "path/to/config.js", // babel 的配置文件,可以不传
    },
  },
};

官方提醒 虽然@babel/eslint-parser可以解析TypeScript,但我们目前不支持使用@babel/eslint-plugin中的规则检测TypeScript。这是因为TypeScript社区以@typescript-eslint为中心,我们希望避免重复工作。此外,由于@typescript-eslint在底层使用TypeScript,所以它的规则可以是类型感知的,这是Babel没有能力做到的。

@typescript-eslint

ESLint 识别的 AST 也就是它默认的 parser 最终转换出来的 AST 数据内容和格式(ESTree),与 typescriptparser 转换出来的 AST 的内容和格式是不一样的,所以 ESLint 是不能识别 typescriptparser 转换出来的 AST 内容。