开启掘金成长之旅!这是我参与「掘金日新计划 · 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的各种规范中,都不允许使用未在代码中声明的变量。但开发中会经常用到一些自带的全局变量。
- 浏览器中的
window、document、console等 - 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
env在ESLint中表示环境,一个环境定义了一组预定义的变量,以便我们在相应环境开发。
可用的环境包括:
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 的环境。此时再使用相关的全局变量,就不会报错未定义了。
ESLint中env的实现也是借助了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-airbnbeslint-config-react- ......
在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。
module.exports = {
"plugins": [
"vue"
]
}
上述就是针对vue所开发的第三方插件,完整的名称是eslint-plugin-vue,里面针对vue的特定场景开发了一些规则。
需要注意的是,plugins仅仅只是加载了插件,并不代表着启用相关的规则。
启用插件需要在rules中明确,或者使用extends
你可以理解为,
plugin只是定义了一些函数的实现方法,具体的调用还是需要在rules或extends中
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-airbnbeslint-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 提供的实验性(例如新功能)和非标准(例如Flow或TypeScript类型)语法。
@babel/eslint-parser 是允许 ESLint 在由 Babel 转换的源代码上运行的解析器。
当你使用 babel 时,babel 的解析器会把你的 code 转换为 AST,该解析器会将其转换为 ESLint 能懂的 ESTree。
该 praser 的 parserOptions 默认配置如下:
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),与 typescript 的 parser 转换出来的 AST 的内容和格式是不一样的,所以 ESLint 是不能识别 typescript 的 parser 转换出来的 AST 内容。