背景
目前 ESLint 的最新版本为 v8.57.0,v9.0.0 已进入 rc 阶段。
ESLint Flat Config 在 2022 年就出现了,在当前版本已内置可选,并会在下个大版本作为默认方案,关于它的详细介绍可参考这篇博客:ESLint’s new config system
第一次尝试
24 年 1 月份做过一次迁移尝试,没有成功。
文档中的迁移指南讲得是挺详细的,但是我折腾很久也没搞明白。
项目里依赖了很多第三方 ESLint 的插件(比如 eslint-plugin-vue、typescript-eslint 等),我不懂怎么才能让这些还没有适配 Flat Config 的插件也融入到我的配置中。直接使用会报错,用 FlatCompat 进行扩展也没有成功。
当时去翻了几个比较常用的 ESLint 插件的仓库,它们主要提供了以下几种策略:
- 1、完全使用 Flat Config 方式重写配置,做 major 升级,不再兼容旧的配置。
- 2、未进行适配,建议使用者自己通过 FlatCompat 方法做兼容。
- 3、将导出的 API 复制成双份,增加 Flat 前缀/后缀做区分。
第二次尝试
也就是今天。
之前注意到 antfu 大佬自己的 antfu/eslint-config 插件已经迁移到 ESLint Flat Config 了,相比较而言我自己的插件配置则简单太多了,参考他的代码应该很容易迁移。
最近发现他的另一个 antfu/eslint-flat-config-viewer 仓库非常有趣,可以查看当前项目里配置的规则,今天一打开发现它已经被收编到 ESLint 官方组织下了。这个项目又激起了我的兴趣,今天必须把迁移工作拿下!
(闲扯:ESLint 新的方案搞了那么久了都没怎么推广开,远不如找些有号召力的大佬以及一些流行项目合作。对于我个人来说,是 Vite 废弃了 CJS 用法才真正促使我将自己的项目里所有的 require 清理掉)
首先介绍一下我的项目目录结构:
- packages
- pkg1
- pkg2
- my-eslint-config
- index.js // 自定义的 ESLint 共享配置
- package.json
- .eslintrc // 整个项目的旧版 ESLint 配置文件
- packages.json
迁移过程主要有以下两步:
1、项目配置文件迁移
旧的 .eslintrc
{
"root": true,
"extends": ["my-eslint-config"], // 这里使用了我自己的 eslint 包(准确的说叫「可共享配置」)
"ignorePatterns": ["docs/**"]
}
新的 eslint.config.js
import MyConfig from "my-eslint-config";
export default [
// 整体结构由对象变为数组,我自己的 eslint 共享配置也应该以数组形式使用
...MyConfig,
{
// 不再需要 root: true,新的位置系统下,配置文件所在目录默认为 root
ignores: ["docs/**"]
}
];
2、共享配置文件迁移
修改前:
module.exports = {
// 使用了 eslint、eslint-plugin-vue、eslint-plugin-prettier 三个包的共享配置
extends: [
"plugin:vue/base",
"eslint:recommended",
"plugin:vue/vue3-recommended",
"prettier"
],
// 使用 eslint-plugin-vue 的自定义解析器
parser: "vue-eslint-parser",
parserOptions: {
// ...
},
plugins: ["vue", "@typescript-eslint"],
env: {
// ...
},
// 一些全局变量配置
globals: {
// ...
},
// 对插件里的特殊规则进行自定义
rules: {
// ...
}
};
修改后:
import pluginJs from "@eslint/js";
import pluginVue from "eslint-plugin-vue";
import pluginTs from "typescript-eslint";
import stylistic from "@stylistic/eslint-plugin";
import parserVue from "vue-eslint-parser";
import parserTs from "@typescript-eslint/parser";
export default [
// eslint 默认推荐规则
pluginJs.configs.recommended,
// 使用了 stylistic 作为样式规则,此次迁移时我抛弃了 prettier
stylistic.configs.customize(),
// ts 默认推荐规则
...pluginTs.configs.recommended,
// vue 默认推荐规则
...pluginVue.configs["flat/recommended"],
{
languageOptions: {
parser: parserVue,
globals: {
// ...
},
parserOptions: {
// ...
}
}
},
{
// 对插件里的特殊规则进行自定义
rules: {
// ...
}
}
];
很顺利地就迁移完成了,主要原因是这里面使用到的第三方插件的最新版本都已经提供了 ESLint Flat Config 的使用方式,使用起来似乎更简单了。
其中,很幸运的,eslint-plugin-vue
插件在 5 天前发布的新版本中刚刚支持 ESLint Flat Config。
Stylistic
当然,在我这次迁移前后,并没有保证完全一致的表现。
一个主要的改变就是将 eslint-plugin-prettier 更换为了 stylistic,主要原因如下:
- 1、关于 ESLint 是否应该做代码的格式化,一直有争议。ESLint 官方打算将这些与格式化有关的规则(比如 semi、indent 等)从原本的核心规则中剥离出来,这些规则在 ESLint 的 v8.53.0 版本之后就已经被标记为 deprecated 了,主要功能目前被社区项目 stylistic 接手。
- 2、一个 JS 项目通常会使用 Prettier 进行代码格式化,同时又会使用 ESLint 进行错误校验。在上述规则被剥离之前,二者的部分逻辑是会冲突的,所以有 eslint-plugin-prettier 这个插件的出现,它会把冲突的部分规则禁用。
- 关于这一点,antfu 大佬有一篇文章:Why I don’t use Prettier
我之前的文章《写个插件(一)Prettier 插件》中也介绍了一个类似的场景:Prettier 对于 Markdown Table 的格式化方案不太好,它会频繁产生可读性差的 git diff 记录,所以我写了插件去修改这个逻辑。
对于 JS 代码的格式化:
- ESLint 可以高度自定义,并且 stylistic 已经提供了这个默认方案
- Prettier 简单配置就挺好,但是很难自定义
所以我将项目中 Prettier 的生效范围做了调整,只处理样式与 md 文档,而对于其他项目代码则交由基于 ESLint 的 stylistic 进行处理。
最后
由于去掉了 eslint-plugin-prettier,会有一些未知的规则突然被启动,再加上 stylistic 也内置了大量新的规则,接下来的工作就是对这些规则做出筛选,合适的保留,不合适的去除。
每次 format 当然都会产生巨大的 git 记录,不过还好有 git blame ignore。