旧架构是一个相当简单的版本,它只支持正常阶段的加载器。投放加载器没有被考虑。旧版本的基本概念是将正常的加载器转换为可以从 Rust 端调用的原生函数。此外,出于性能考虑,Rspack 还从 JS 端组合加载器,以减轻 Node/Rust 通信的性能问题。
在这个新架构中,加载器不会直接转换为原生函数。相反,它与 webpack 的 loader-runner 如何解析其加载器几乎相同,利用标识符。每次 Rspack 想要调用 JS 加载器时,标识符将被传递给 Node 端传递的处理程序以进行处理。该实现还保留了出于性能原因组合 JS 加载器的功能。
重构没有引入任何其他破坏性更改。因此它向后兼容。架构的更改也有助于我们实现可组合的投放加载器。
投放加载器是一种改变加载器管道流程的技术。它通常与内联加载器语法一起使用,用于创建另一个加载器管道。style-loader 等以及可能使用该技术消耗后续加载器评估结果的其他加载器。还有其他技术可以实现相同的功能,但超出了本文的范围。
有关更多详细信息,请参阅 投放加载器。
在加载器的原始实现中,Rspack 首先会转换正常的加载器,然后将其传递给 Rust 端。在构建模块的过程中,这些加载器将被直接调用。
加载器运行器仅位于 Rust 端,并直接从 Rust 端执行加载器。这种机制对我们使用 webpack 的 loader-runner 来组合加载器有很大的限制。
在新架构中,我们将从 Rust 核心将加载器请求委托给位于 JS 端的调度器。调度器将规范化加载器并使用 webpack 的修改版 loader-runner 执行它们。
用于投放或正常的加载器函数不会传递给 Rust 端。相反,每个 JS 加载器都有其标识符来唯一地表示每一个。如果一个模块请求加载器来处理该模块,Rspack 将将标识符与选项传递给 JS 端以指示类似 Webpack 的 loader-runner 处理转换。这也降低了编写我们自己的加载器组合器的复杂性。
选项通常将被转换为查询,但一些选项包含无法序列化的字段,Rspack 将重用由 webpack 创建的 加载器标识 来唯一地识别选项并在以后的加载过程中恢复它。
如我们之前所知,每个加载器都有两个步骤:投放和正常。为了获得性能友好的互操作性,我们必须尽可能减少 Rust 和 JS 之间的通信。通常,加载器的执行步骤将如下所示
上面加载器的执行顺序将如下所示
上面的示例不包含任何 JS 加载器,但如果,比如,我们标记这些注册在 JS 端的加载器
执行顺序不会改变,但 Rspack 将组合步骤 2/3/4 以便只有一轮通信。