Skip to content

ESLint Flat Config 迁移过程

Published:

背景

目前 ESLint 的最新版本为 v8.57.0,v9.0.0 已进入 rc 阶段。

ESLint Flat Config 在 2022 年就出现了,在当前版本已内置可选,并会在下个大版本作为默认方案,关于它的详细介绍可参考这篇博客:ESLint’s new config system

第一次尝试

24 年 1 月份做过一次迁移尝试,没有成功。

文档中的迁移指南讲得是挺详细的,但是我折腾很久也没搞明白。

项目里依赖了很多第三方 ESLint 的插件(比如 eslint-plugin-vuetypescript-eslint 等),我不懂怎么才能让这些还没有适配 Flat Config 的插件也融入到我的配置中。直接使用会报错,用 FlatCompat 进行扩展也没有成功。

当时去翻了几个比较常用的 ESLint 插件的仓库,它们主要提供了以下几种策略:

第二次尝试

也就是今天。

之前注意到 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,主要原因如下:

我之前的文章《写个插件(一)Prettier 插件》中也介绍了一个类似的场景:Prettier 对于 Markdown Table 的格式化方案不太好,它会频繁产生可读性差的 git diff 记录,所以我写了插件去修改这个逻辑。

对于 JS 代码的格式化:

所以我将项目中 Prettier 的生效范围做了调整,只处理样式与 md 文档,而对于其他项目代码则交由基于 ESLint 的 stylistic 进行处理。

最后

由于去掉了 eslint-plugin-prettier,会有一些未知的规则突然被启动,再加上 stylistic 也内置了大量新的规则,接下来的工作就是对这些规则做出筛选,合适的保留,不合适的去除。

每次 format 当然都会产生巨大的 git 记录,不过还好有 git blame ignore。