迁移至 v6.0.0
ESLint v6.0.0 是 ESLint 主要发行版。在此版本中有一些破坏性变更,而本指南旨在引导你了解这些变化。
下列内容大致按每项变化预计影响的用户数量排序,其中第一项为预计会影响最多的用户的变化。
面向用户的破坏性变更
- 不再支持 Node.js 6
- 更新
eslint:recommended
- 插件和可共享配置不再受 ESLint 位置影响
- 默认解析器将更严格地验证选项
- 规则配置验证更严格了
no-redeclare
规则的默认值更严格了comma-dangle
规则的默认值更严格了no-confusing-arrow
规则的默认值更宽松了- 配置文件中的
overrides
将匹配点文件 - 扩展配置文件中的
overrides
现在可以被父级配置文件所覆盖 - 现在验证配置的全局变量值
- 移除废弃的
experimentalObjectRestSpread
选项 - 规则选项中的正则表达式的 unicode 标志可以解析了
面向插件/自定义规则开发者的破坏性变更
- 插件作者可能需要更新安装指南
RuleTester
现在可以验证规则模式中无效的default
关键字了RuleTester
的parser
选项需要是相对路径- 删除
eslintExplicitGlobalComment
范围分析属性
面向集成开发者的破坏性变更
不再支持 Node.js 6
Node.js 6 在 2019 年 4 月到达了生命的终点,将不再获得安全更新。我们在 ESLint v6 中正式放弃了对它的支持。ESLint 现在支持以下版本 Node.js:
- Node.js 8(8.10.0 以上)
- Node.js 10(10.13.0 以上)
- Node.js 11.10.1 以上
解决方案:在使用 ESLint v6.0.0 前,请确保你至少升级到 Node.js 8。如果你无法升级,我们推荐在能够升级 Node.js 版本前,继续使用 ESLint v5.x。
相关议题:eslint/eslint#11546
更新 eslint:recommended
eslint:recommended
配置添加了下列规则:
no-async-promise-executor
不允许使用async
函数作为Promise
构造函数的参数,因为这通常是个漏洞。no-misleading-character-class
将报告正则表达式中与预期不符的字符类,no-prototype-builtins
将报告调用foo.hasOwnProperty("bar")
等方法(它经常导致漏洞),并推荐使用Object.prototype.hasOwnProperty.call(foo, "bar")
代替之。no-shadow-restricted-names
不允许使用undefined
这样的阴影变量(例如let undefined = 5;
),因为这可能会混淆读者。no-useless-catch
报告多余的catch
语句,可以从代码中删除而不改变其行为。no-with
不允许使用with
语句,这可能使代码难以理解并导致兼容性问题。require-atomic-updates
报告了在异步函数中重新分配变量时可能出现的竞争条件错误。
此外,eslint:recommended
删除了下列规则:
no-console
不允许调用console.log
等函数。虽然这条规则适用于基本情况(例如避免在生产代码中留下调试语句),但它不像eslint:recommended
中的其他规则那样广泛适用,而且在一些情况下是需要使用console.log
的(例如,在 CLI 应用程序中),这使得它错误地进行了报告。
最后,在 ESLint v5 中,eslint:recommended
会明确地禁用所有不被视为“推荐”的核心规则。如果 eslint:recommended
在另一个配置之后加载就会出现问题,因为 eslint:recommended
会关闭一些规则。而在 ESLint v6 中,eslint:recommended
对非推荐的规则没有影响。
**解决方法:**为了模仿 5.x 的 eslint:recommended
行为,你可以在配置文件中明确地禁用/启用规则,如下所示:
{
"extends": "eslint:recommended",
"rules": {
"no-async-promise-executor": "off",
"no-misleading-character-class": "off",
"no-prototype-builtins": "off",
"no-shadow-restricted-names": "off",
"no-useless-catch": "off",
"no-with": "off",
"require-atomic-updates": "off",
"no-console": "error"
}
}
在极少数情况下(如果你依赖以前的行为,即 eslint:recommended
会禁用核心规则),你可能需要禁用其他规则来恢复以前的行为。
相关议题:eslint/eslint#10768、eslint/eslint#10873
插件和可共享配置不再受 ESLint 位置影响
以前 ESLint 基于相对于 ESLint 包本身的位置来加载插件的。因此,我们建议全局安装 ESLint 的用户也应该在全局安装插件,而安装了本地 ESLint 的用户应该在本地安装插件。然而,由于设计错误,这个策略导致 ESLint 在某些情况下随机地不能加载插件和可共享配置,特别是在使用像 lerna
和 Yarn Plug n’ Play 这样的包管理器时。
经验之谈:在 ESLint v6 中,即使是全局 ESLint,也应该在本地安装插件。更确切地说,ESLint v6 默认将基于用户项目进行解析插件,并且总是相对于配置文件进行解析可共享配置和解析器。
解决方案:如果你全局安装了 ESLint (如用 npm install eslint --global
安装)以及插件,你应该在运行 ESLint 的项目中安装这些插件。如果配置文件扩展了可共享的配置和解析器,你应该确保配置文件中包含了这些包依赖。
如果你使用了位于非本地项目的配置文件(使用 --config
标志),可以考虑将插件作为该配置文件的依赖项来安装,并将 --resolve-plugins-relative-to
标志设为该配置文件的位置。
相关议题:eslint/eslint#10125、eslint/rfcs#7
默认解析器将更严格地验证选项
ESLint 使用的默认解析器 espree
,现在会因为以下情况下而引发错误:
ecmaVersion
解析器选项被设置为数字以外的东西,例如字符串"2015"
(以前会忽略非数字的选项)。sourceType: "module"
解析器选项被设置,而ecmaVersion
被设置为5
或未被指定(以前设置sourceType: "module"
将隐性导致ecmaVersion
设置为令人不知所以然的最小值 2015)。sourceType
设置成了"script"
或"module"
以外的值。
解决方案:如果配置将 ecmaVersion
设置为非数字值,你可以删除 ecmaVersion
恢复以前的行为(然而,你可能想仔细检查一下配置是否真的按预期工作)。如果你的配置设置了 parserOptions: { sourceType: "module" }
而没有设置。parserOptions.ecmaVersion
,你应该添加 parserOptions: { ecmaVersion: 2015 }
以恢复以前的行为。
相关议题:eslint/eslint#9687、eslint/espree#384
规则配置验证更严格了
为了更早地发现配置错误,如果你试图配置不存在的规则,ESLint v6 会报告检查错误。
配置 | ESLint v5 | ESLint v6 |
---|---|---|
/*eslint-enable foo*/ |
no error | linting error |
/*eslint-disable(-line) foo*/ |
no error | linting error |
/*eslint foo: 0*/ |
no error | linting error |
{rules: {foo: 0}} |
no error | no error |
{rules: {foo: 1} |
linting warning | linting error |
解决方案:你可以在(内联)配置中删除不存在的规则。
相关议题:eslint/eslint#9505
no-redeclare
规则的默认值更严格了
no-redeclare
规则的默认选项已经从 { builtinGlobals: false }
改为 { builtinGlobals: true }
。此外,对于通过注释启用的全局变量,如 /* global foo */
,如果这些全局变量已经通过配置启用,那么 no-redeclare
规则现在将报告错误。
解决方案:
要恢复该规则以前的选项,你可以按以下方式进行配置:
{
"rules": {
"no-redeclare": ["error", { "builtinGlobals": false }]
}
}
此外,如果你看到代码中的全局变量注释有新的错误,你应该删除这些注释。
相关议题:eslint/eslint#11370、eslint/eslint#11405
comma-dangle
规则的默认值更严格了
以前,comma-dangle
规则会忽略尾部的函数参数,除非明确配置为检查函数逗号。在 ESLint v6 中,函数逗号的处理方式与其他类型的尾随逗号相同。
解决方案:你可以用以下方法将规则恢复成和以前一样的默认行为:
{
"rules": {
"comma-dangle": ["error", {
"arrays": "never",
"objects": "never",
"imports": "never",
"exports": "never",
"functions": "ignore"
}]
}
}
要恢复像 always-multiline
这样的字符串选项以前的行为,请将上面例子中的 never
替换为 always-multiline
。
相关议题:eslint/eslint#11502
no-confusing-arrow
规则的默认值更宽松了
The default options for the no-confusing-arrow
rule have changed from { allowParens: false }
to { allowParens: true }
.
解决方案:你可以用以下方法将规则恢复成和以前一样的默认行为:
{
"rules": {
"no-confusing-arrow": ["error", { "allowParens": false }]
}
}
相关议题:eslint/eslint#11503
配置文件中的 overrides
将匹配点文件
由于一个错误,在配置文件的 overrides
部分的 files
列表中的 glob 模式永远不会与 dotfiles
相匹配,这使得 overrides 无法应用于以点开始的文件。这个错误已经在 ESLint v6 中被修复。
解决方案:如果你不希望 dotfiles 被覆盖匹配,可以考虑在 overrides
部分添加类似 excludedFiles: [".*"]
的内容。更多细节见文档。
相关议题:eslint/eslint#11201
扩展配置文件中的 overrides
现在可以被父级配置文件所覆盖
由于错误,以前可共享配置中 overrides
块优先于父配置。例如在下面的配置设置中,semi
规则最终会被启用,尽管它在最终用户的配置中被明确禁用。
// .eslintrc.js
module.exports = {
extends: ["foo"],
rules: {
semi: "off"
}
};
// eslint-config-foo/index.js
module.exports = {
overrides: {
files: ["*.js"],
rules: {
semi: "error"
}
}
};
在 ESLint v6.0.0 中,父级配置总是优先于扩展配置,即使有 overrides
块。
解决方案:我们预计这个问题的影响非常小,因为大多数可共享配置不使用 overrides
块。然而,如果你使用带有 overrides
块的可共享配置,你可能会遇到由于配置中明确指定的内容而导致的行为变化,但直到现在还没有活动。如果你想继承可共享配置的行为,只需从你自己的配置中删除相应的条目(在上面的例子中,可以删除 .eslintrc.js
中的 semi: "off"
以恢复之前的行为)。
相关议题:eslint/eslint#11510
现在验证配置的全局变量值
以前,当用对象配置一组全局变量时,有可能使用任何东西作为对象的值。未知的值将视作 "writable"
。
// .eslintrc.js
module.exports = {
globals: {
foo: "readonly",
bar: "writable",
baz: "hello!" // ???
}
};
有了这个变化,globals
对象中的任何未知值都会导致配置验证错误。
解决方案:如果你在更新后看到与全局变量有关的配置验证错误,请确保为 globals 配置的所有值都为 readonly
、writable
或 off
(ESLint 也支持替代性的拼写和变体,以保证兼容性)。
移除废弃的 experimentalObjectRestSpread
选项
以前,使用默认的解析器时,配置可以使用 experimentalObjectRestSpread
选项来启用对对象剩余展开属性的解析支持。
{
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
}
从 ESLint v5 开始,ecmaFeatures: { experimentalObjectRestSpread: true }
已经等同于 ecmaVersion: 2018
,并且还发出了废弃警告。在 ESLint v6 中,已经完全无损地删除了experimentalObjectRestSpread
功能。如果你的配置是依靠 experimentalObjectRestSpread
来启用 ES2018 解析,你可能会开始看到最新的语法的解析错误。
解决方案:如果你使用 experimentalObjectRestSpread
选项,你应该修改配置来进行替换:
{
"parserOptions": {
"ecmaVersion": 2018
}
}
如果你不确定哪个配置文件需要更新,可以尝试运行 ESLint v5 并查看废弃警告中提到的配置文件。
相关议题:eslint/eslint#9990
规则选项中的正则表达式的 unicode 标志可以解析了
像 max-len
这样的规则支持字符串选项,它被解释为正则表达式。在 ESLint v6.0.0 中,这些正则表达式被解释为 unicode 标志,在匹配星形符号等字符时,应该表现出更合理的行为。Unicode 正则表达式也比非 unicode 正则表达式更严格地验证转义序列。
解决方案:如果你在升级后得到规则选项的验证错误,请确保你的规则选项中的任何正则表达式没有无效的转义序列。
相关议题:eslint/eslint#11423
插件作者可能需要更新安装指南
如果你维护一个插件并提供安装说明,你应该确保安装说明是最新的面向用户的插件加载方式的变化。特别是,如果你的插件是用 generator-eslint
包生成的,它很可能包含了过时的说明,即如何在全局 ESLint 安装中使用该插件。
相关议题:eslint/rfcs#7
RuleTester
现在可以验证规则模式中无效的 default
关键字了
在某些情况下,规则模式可以使用 default
关键字来自动指定规则选项的默认值。然而,default
关键字只在特定的模式位置有效,而在其他地方被忽略,如果规则错误地期望提供默认值作为规则选项,就会由产生错误的风险。在 ESLint v6.0.0 中,如果规则模式中有无效的 default
关键字,RuleTester
将引发错误。
解决方案:如果 RuleTester
开始报告关于无效默认值的错误,你可以在你的规则模式中删除指定位置的 default
属性,规则将以同样的方式行事(如果发生这种情况,你可能还想验证一下,当该位置没有提供选项值时,该规则的行为是否正确)。
相关议题:eslint/eslint#11473
RuleTester
的 parser
选项需要是相对路径
为了在测试中使用自定义解析器,我们可以使用 parser
属性,并给出包名或文件路径。然而,如果给了包名,测试区会搞不清楚应该从哪加载解析器包,因为测试器不知道哪些文件在运行测试器。在 ESLint v6.0.0 中,RuleTester
不允许 parser
属性带有包名。
解决方案:如果你在测试用例中将 parser
属性指定为包名,请用 require.resolve()
函数更新它,将包名解析为包的绝对路径。
相关议题:eslint/eslint#11728、eslint/eslint#10125、eslint/rfcs#7
删除 eslintExplicitGlobalComment
范围分析属性
以前,ESLint 会在范围分析中为 Variable
对象添加 eslintExplicitGlobalComment
属性,以表明变量是由于 /* global */
注释而引入的。这个属性并没有任何记录,同时 ESLint 团队也无法在 ESLint 核心中找到这个属性的任何用法。该属性在 ESLint v6 中被删除,取而代之的是 eslintExplicitGlobalComments
属性,如果变量在声明时有多个注释,该属性可以列出所有 /* global */
注释。
解决方案:如果你维护的规则使用了 eslintExplicitGlobalComment
属性,请使用 eslintExplicitGlobalComments
属性替换。
相关议题:eslint/rfcs#17
Linter
不再尝试从文件系统中加载缺少的解析器了
以前,当用以前没有定义过的解析器检查代码时,Linter
API 会尝试从文件系统加载解析器。然而,这种行为令人困惑,因为 Linter
在其他情况下都不会访问文件系统,而且很难确保从文件系统加载解析器时能找到正确的解析器。
在 ESLint v6 中,Linter
将不再执行任何文件系统操作,包括加载解析器。
解决方案:如果你使用了 Linter
和自定义解析器,请改用 Linter#defineParser
,并在检查代码前明确定义解析器。
相关议题:eslint/rfcs#7