ESLint 的未来展望

新的配置系统仅仅是 ESLint 即将到来的重大变化的开端。

当我们于四月份发布 ESLint v9.0.0 时,这是 30 个月以来的第一个主要版本,并正式引入了新的 配置 系统。 ESLint v9.0.0 还进行了一些规则 API 更改,为核心功能的未来发展做准备。发布后,我们花费了大量时间创建兼容性实用程序配置迁移工具规则 API 转换实用程序,以帮助生态系统迁移到 ESLint v9.0.0。所有这些工作对于我们继续进行 ESLint 即将到来的重大变更都是必要的。

语言插件

两年前,TSC 决定是时候开放 ESLint,使其可以检查 JavaScript 以外的语言。实际上,ESLint 核心做了很多与 JavaScript 无关的事情:查找和读取文件、加载特定于文件的配置、收集规则冲突、将结果输出到控制台等等。此外,我们不断发现一些插件在 ESLint 内部检查其他语言(例如 GraphQLHTML),通过与 JavaScript 相同的逻辑传递不同的 AST。这是低效且容易出错的,必须有一种更好的方法。

2023 年,语言插件 RFC 获得正式批准。然而,为了实施此 RFC,我们需要正式发布新的配置并进行一些规则 API 更改。特别是规则 API 更改,对于分离 ESLint 核心正在做的事情以及语言插件将为自定义规则提供什么至关重要。在完成这两项更改后,我们开始了繁琐的重构 ESLint 核心的任务,将特定于 JavaScript 的部分从与语言无关的部分中提取出来。

以下是未来的预期(没有具体时间表,因为一切都取决于贡献者的可用性)

  • @eslint/js - 我们将逐步将所有与 JavaScript 相关的功能移至 @eslint/js 包中,包括规则和文档。我们将重用现有的 Espree repo 并将其转换为包含 Espree、eslint-scopeeslint-visitor-keys 和所有核心 JavaScript 规则的 monorepo。这将使我们能够在单个 repo 中处理所有与 JavaScript 相关的内容。
  • @eslint/json - 我们的第一个语言插件将允许 ESLint 本地检查 JSON 文件。此插件将包含解析逻辑以及所有相关的规则和文档。与 @eslint/js 类似,这将使我们拥有一个专注于 JSON 检查的单一 repo,进一步将任何特定于语言的功能从核心中移出。
  • @eslint/markdown - eslint-plugin-markdown 将重命名为 @eslint/markdown,以便更好地与其他包对齐。我们将添加检查 Markdown 的能力以及特定于 Markdown 的规则。

当前的计划是拥有这三个官方 ESLint 语言插件,希望它们可以作为生态系统开发更多语言插件的示例。

随着特定于语言的功能被提取到单独的存储库中,剩下的任务就是完全重写核心。

核心重写

自 11 年前 ESLint 首次创建以来,ESLint 存储库中代码的架构并没有发生太大变化。因此,积累了大量的技术债务,阻碍了我们进行一些我们想做的更改。我们目前面临的一些问题:

  • 同步核心逻辑。 Linter 类是完全同步的,这意味着我们无法支持异步规则或异步解析,这是我们经常收到的两个功能请求。我们需要添加第二个异步工作的类,或者向 Linter 添加异步工作的替代方法。这两种选择看起来都需要大量工作,实际上相当于重写核心的大部分内容。
  • 有限的 API。 公共 API 是有限的,因为 ESLint 最初从未打算用作 API。最初的 linter 对象仅用于启用浏览器演示。后来它被 Linter 类取代,甚至更晚又出现了 ESLint 类,以完全模仿命令行界面。当我们想要公开新功能时,它需要存在于这两个听起来相似的 API 之一中,不幸的是,主要决策点是 API 是否需要在浏览器中可用。如果是,则需要放在 Linter 中,否则需要放在 ESLint 中。这既令人困惑,从长远来看也是不可持续的。
  • 缺乏类型检查。 我们一直希望在存储库中添加类型检查以帮助捕捉潜在问题,但过去尝试这样做需要大量工作和协调。最终,我们得出结论,这不值得付出努力。
  • 停留在 CommonJS 中。 与类型检查情况类似,虽然有人希望将代码库转换为 ESM,但这样做需要花费大量的工作。我们将花费大量时间进行转换,最终得到的只是等效的功能集。

在考虑了持续增量更改现有核心或从头开始的选项后,我们决定是时候从头开始了。虽然我们坚信完全重写代表着巨大的风险,但在经历了 11 年之后,我们可以诚实地说,我们从最初的架构中获得了最大的收益。

展望未来,以下是您可以期待的:

  • 一个新的存储库。 eslint/rewrite 存储库是我们与语言无关的工作的新家。它是一个 monorepo,我们将在其中管理所有以某种方式直接与核心相关的包。
  • 现代化的包。 eslint/rewrite 中的每个包都将达到现代标准,发布 ESM 入口点以及类型定义。如果可能,我们还将发布 CommonJS 入口点。所有包都发布了 provenance 到 npm 和 JSR(如果适用)。
  • 运行时无关的核心。 @eslint/core 包将包含 ESLint 的运行时无关 API 以及核心的类型定义。我们将随着新 API 的设计,逐步构建此包,从 eslint 包中提取功能片段。随着每年涌现出更多的 JavaScript 运行时,我们认为运行时无关的核心变得越来越重要。
  • 可组合的 API。 新的 API 不会将所有功能捆绑到一个或两个类中,而是可组合的,许多专门构建的类旨在一起使用。类将遵循单一职责原则,从而更容易进行更改和在集成内部自定义 ESLint。
  • 新的 CLI。 我们将在 @eslint/node 包中从头开始重写 CLI。我们将从最常见的用例开始,并重新评估每个标志,以确保它对于与语言无关的核心仍然有意义。使用不同的包名称使我们可以在不中断 eslint 包使用的情况下试验新的 CLI。此包还将导出其他特定于 Node.js 的 API。
  • 并行开发。 我们将继续并行维护 eslint 和重写,这样我们就不会为了全新的东西而牺牲现有的包。目标是使 eslint 包逐渐变小,并利用 @eslint/core 中包含的 API,以便我们尽可能地限制重复。

结论

我们对 ESLint 的未来发展方向感到非常兴奋,因为我们认为这代表了 ESLint 发展的下一个合乎逻辑的步骤。将 ESLint 转变为任何人都可以为其编写插件的与语言无关的 linter,将通过减少任何一个项目所需的 linter 工具和编辑器扩展的数量来简化开发。此外,将我们的核心重写为更可组合的 API 可以实现更轻松和更可定制的集成,并拥有我们自己的类型定义,以确保与 API 的兼容性。

ESLint 以其当前的架构经历了 11 年,我们希望这些变化能帮助我们度过未来的 11 年。

最新的 ESLint 新闻、案例研究、教程和资源。

Evolving flat config with extends
5 分钟阅读

使用 extends 改进扁平配置

您的 eslint.config.js 文件现在可以使用 extends 来简化您的配置。

ESLint v9.22.0 released
1 分钟阅读

ESLint v9.22.0 发布

我们刚刚推送了 ESLint v9.22.0,这是一个 ESLint 的次要版本升级。此版本添加了一些新功能并修复了先前版本中发现的几个错误。

ESLint v9.21.0 released
2 分钟阅读

ESLint v9.21.0 发布

我们刚刚推送了 ESLint v9.21.0,这是一个 ESLint 的次要版本升级。此版本添加了一些新功能并修复了先前版本中发现的几个错误。