Skip to content

Design flaws

1. Transform Hook

rollup 的钩子判断和执行逻辑均在 transform 钩子中,也就是说每一个钩子的 transform 钩子都会为每一个模块执行一遍。这对于原生 bundler 来说并不可取,若原生 bundler 也借鉴了该设计,那么会存在性能问题。原生 bundler 会频繁与 javascript 通讯并调用 javascripttransform 钩子,即使这个模块的处理逻辑不在这个插件的 transform 钩子中。原生 bundler 调用单线程的 javascript 是十分昂贵的性能开销,通信开销在上万个模块通信场景下将会十分巨大,尤其是在 HMR 下,这将更难以接受。

esbuild 为例,模块需要先经过 filter 正则逻辑的过滤后,允许的正则表达式语法是 go 的正则表达式引擎支持的语法。这与 javascript 略有不同,go 的正则表达式并不支持前瞻(look-ahead)、后顾(look-behind)和反向引用(backreference)。go 的正则表达式引擎设计目的是避免部分会导致 javascript 灾难性指数时间最坏情况的性能问题。若命中 filter 逻辑,则 go 会与 javascript 通信并回调 javascripttransform 钩子,性能开销低的同时避免了大量 go 端与 javascript 端的通信。

Bundler的设计取舍 一文中也提到 rspack 也认同了 esbuild 的插件与原生通讯设计。

2. Incremental Build

rollup 增量更新类似于 reactfiber 树的增量更新,自顶而下的进行检测,对于入口模块每次都会调用 resolveId,同时对于每一个模块都会执行 load 钩子,这的确与初始冷启动相比减少了 resolveIdtransform 钩子的执行次数。但对于每一个模块都需要执行 load 钩子,这在大量模块的场景下,是十分消耗性能的。

rollup issue 2182rollup issue 3728 中可以看到,rollup 目前对于硬盘空间上的持久性缓存(Persistent Cache)还不支持,也就是说 rollup 目前只支持对于 watch 模式下的增量更新,而不支持再次冷启动时的增量更新。webpack 支持了 Persistent Cache,这也是 webpack 在二次冷启动上胜过 rollup 的原因之一。

Discuss

Released under the MIT License. (ee0e562)