前段时间 ESLint 团队在 Github 上做出了一项重要决定,在未来将要放弃部分规则的维护,并希望通过社区去维护这些工作。于是,antfu 大佬决定通过 ESLint Stylistic 项目来迁移并维护这些工作。
最近我发现,antfu 对他维护的 @antfu/eslint-config
配置也同步做了重大升级,并采用了 ESLint 全新的扁平化配置来重构 eslint-config
。关于 ESlint 的扁平化配置我是第一次听说,于是深入的学习了一波。
配置扁平化
在 2013 年 ESLint 首次发布时,配置起来相当简单,但是经过多年的迭代,配置系统变得一团糟(官方说的)。因此,ESLint 团队决定创建一个新的配置系统(flat config
)来解决这些问题。这个想法最早在 2022 年就提出了,然而到了 2023 年我才了解到它 o(╥﹏╥)o。
如果你对背景感兴趣,可以查看 《ESLint's new config system》 这篇文章。
新的配置文件
旧的配置系统中支持多种格式的配置文件,比如:
.eslintrc
.eslintrc.json
.eslintrc.js
后文中统称为
eslintrc
在扁平化配置中,使用了全新的配置文件名标准:
eslint.config.js
扁平化配置只支持一种配置文件,这样可以减少读取和解析配置文件的时间。如果项目中同时存在两种配置文件,它会首先尝试加载 eslint.config.js
文件。如果没有找到,它将再去查找 .eslintrc*
文件。
这是一个实验性功能。你可以在项目根目录创建 eslint.config.js 文件或将
ESLINT_USE_FLAT_CONFIG
环境变量设置为true
来开启这项功能。
VSCode 默认情况下是不支持扁平化配置的,我们需要在 .vscode/setting.json
中设置:
json
{
"eslint.experimental.useFlatConfig": true
}
支持 ESM 语法
在 eslintrc 中,我们只能编写CJS语法。但是如果你使用新的配置文件,你可以选择使用 ESM 或 CJS 两种语法编写配置文件。
与旧的 eslintrc 配置不同,新的配置文件将返回一个配置数组,而不是一个对象。
eslintrc
配置文件写法:
js
// .eslintrc.js
module.exports = {
// your config
}
扁平化配置使用 CJS 写法:
js
// eslint.config.js
module.exports = [
{ // your config },
{ // your config },
]
扁平化配置使用 ESM 写法:
js
// eslint.config.js
export default [
{ // your config },
{ // your config },
]
不再需要 overrides
在旧的 eslintrc 中,如果需要对特定文件进行单独配置,需要使用 overrides 字段。例如:
js
module.exports = {
overrides: [
{
files: ["*.js", "*.mjs"],
ignorePatterns: ["**/mocks/*.ts"],
rules: {
// some rules
},
}
]
}
而在扁平化配置中,每个配置对象都有可选的 files
和 ignores
字段,用于指定基于最小匹配的 glob模式
来匹配文件。因此,我们不再需要 overrides
字段来进行实现覆盖了。(每个文件就像是单独配置的。)
js
export default [
{
files: ["**/*.js"],
ignores: ["**/*.test.js"],
},
{
files: ["**/*.ts"],
ignores: ["**/*.test.ts"],
}
];
如果您有两个配置对象匹配相同的文件并定义了冲突的规则,有效的配置对象将始终是最后一个,和上文中配置的解析逻辑是相同的。
有了
files
和ignores
字段,感觉以后.eslintignore
文件和eslint --ext .js,.vue
参数基本上不需要了。
移除 extends
在旧的 eslintrc 配置中,extends
字段允许用户导入另一个配置,然后对其进行扩展。假设我们想使用 eslint-config-vue
的配置:
在旧的 eslintrc
配置中:
js
module.exports = {
extends: ['vue'],
rules: {
"vue/block-order": "off",
// 添加自己的 `rules` 设置
}
}
如果使用扁平化配置,我们需要这样做:
js
import vueConfig from "eslint-config-vue"
export default [
vueConfig, // <--这里
{
files: ["**/*.js", "**/*.cjs"],
rules: {
"semi": "error",
"no-unused-vars": "error"
}
},
]
注意:
-
在旧的 eslintrc 配置中,当使用
extends
导入共享配置时,extends 值是一个字符串,并且不需要手动引入,只需在项目中安装该包即可。 -
在扁平化配置中,当导入共享配置时,我们需要手动
import
该配置,并将其添加为配置数组中的一项使用。
在扁平化配置中,建议将外部配置首先插入到数组中,以便它成为该文件的配置基础。因为配置的解析顺序是从数组的顶部向下到底部进行的,ESLint 会组合两个 config 对象来创建文件的最终配置,当遇到配置冲突时,后面的配置会覆盖前面的。
新的插件配置
扁平化配置中使用插件和在 eslintrc 中使用非常相似。最大的区别是 eslintrc 使用字符串 ,而扁平化配置使用对象。这与上面共享配置遵循相同的原则。例如:
js
import vue from "eslint-plugin-vue";
export default [
{
files: ["**/*.vue"],
plugins: {
vue
}
rules: {
"vue/block-order": "off",
}
}
]
插件支持重命名
在上面的配置中,我们使用插件 eslint-plugin-vue
,并使用 vue 变量导入作为 plugins
配置的值。
与 eslintrc 中使用插件不一样的是,扁平化配置中没有严格的插件名称,支持插件重命名。当我们想要覆盖插件内部的规则时,使用 plugins 的键作为命名空间,比如:
js
import vue from "eslint-plugin-vue";
import ts from "@typescript-eslint/eslint-plugin";
export default [
{
files: ["**/*.vue"],
plugins: {
newName: vue,
ts
}
rules: {
"newName/block-order": "off",
}
}
]
在 @antfu/eslint-config
中多处使用了这个特点,使规则看起来更加一致,使用时不需要关心它们来自哪个插件。当你要覆盖规则或内联禁用规则时,需要更新为新前缀:
diff
-// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+// eslint-disable-next-line ts/consistent-type-definitions
type foo = { bar: 2 }
移除 env 选项
在旧的 eslintrc 配置中,为了让 eslint 支持 NodeJS 相关的全局变量,我们需要这么做:
js
module.exports = {
env: {
node: true,
},
};
但是在扁平化配置中已经不需要了。另外,我们可以在 globals
属性中定义可用的全局变量:
js
export default [
{
files: ["**/*.js"],
languageOptions: {
globals: {
wx: "readonly",
},
},
},
];
除此之外,ESLint 团队建议我们使用一个名为 globals 的包,该包从ESLint中提取了所有环境信息:
js
import globals from "globals";
export default [
{
files: ["**/*.js"],
languageOptions: {
globals: {
...globals.browser,
myCustomGlobal: "readonly"
}
}
}
];
新的 language option
在扁平化配置中,所有与JavaScript相关的配置项移动到一个名为 languageOptions
的新顶级选配置中,主要选项如:
- ecmaVersion
- sourceType
- globals
- parser
- parserOptions
js
export default [
{
files: ["**/*.js"],
languageOptions: {
ecmaVersion: 2021,
sourceType: "module",
globals: {},
parser: babelParser,
parserOptions: {
babelOptions: {},
},
},
},
];
总结
本文主要分享学习 ESLint 新扁平化配置系统的一些总结。新的配置系统使得 ESLint 配置更加简洁和灵活,并提供了更好的可扩展性和可定制化。如果你对此感兴趣,强烈建议阅读官方文档,了解更多新特性和新变化。