[译] 一个关于打包工具的故事:从 webpack 迁移到 Rspack在 Alan 公司,我们多年来一直使用 webp
本文翻译自 A bundler story: migrating from webpack to Rspack,原作者 Tim Petricola。
在 Alan 公司,我们多年来一直使用 webpack。虽然它很好地为我们服务,但它已经成为开发的瓶颈。
最近,我们完成了向 Rspack 的迁移(Rspack 是一个承诺提供更快性能的 Rust 替代品)。
这篇文章是我们旅程和经验的简短故事。
选择一个打包工具
打包工具是将代码和依赖项打包成若干个 JavaScript 文件的工具,它可以优化性能和浏览器加载速度。
当 Alan 公司在 2016 年启动时,webpack 是 JavaScript 打包工具的事实标准。它经过了实战考验,拥有庞大的生态系统,并且有非常丰富的配置项。
虽然 webpack 多年来很好地为我们服务,但它已成为开发的瓶颈。我们的本地构建和热模块替换 (HMR) 不够快:
- 第一次服务器启动需要 45 秒。
- HMR 需要 15 秒才能完成。
- 生产环境构建在 CI 上超过 5 分钟。
这些年来,我们通过在配置中引入 webpack 的持久化缓存,用 esbuild 替换 Babel 和 Terser 等方式进行改进。但这逐渐达到了一个瓶颈,在不进行重构的情况下,我们已经无法获得更多的性能提升。
为了改进开发和生产的 feedback loop(反馈循环),我们需要寻找一个新的打包工具。
近年来,JavaScript 生态系统中出现了许多新的构建工具—— Parcel、Vite、esbuild、Rspack、Turbopack、Farm、Mako 等。这些工具都承诺在开发者体验和性能方面具有它们的优势。
但在 Alan,我们喜欢无聊的技术。我们不想使用需要工程师深入研究新概念、或花时间克服工具问题的前沿技术。我们在了解两个新的打包工具 —— Vite 和 Rspack 时牢记这一原则。
Vite
我们过去曾探索过切换到 Vite,因为它在 React 生态系统中已经成为一个非常流行的工具。Vite 是一个很棒的工具,采用了不同的实现,因为它在开发时不打包资源,提供更快的服务器启动时间和 HMR。然而,我们发现 Vite 并不适合我们:
- Vite 在开发和生产构建时依赖不同的工具(开发时使用 esbuild,生产时使用 Rollup)。这可能导致开发和生产构建之间出现差异,并且在构建过程中调试问题变得很难。
- Vite 在开发时不打包的方式,经常会导致我们应用程序中的模块数量过多,而引起浏览器网络拥塞。虽然这可以优化,但这耗费了我们不愿意花费的时间。
- Vite 与 webpack 非常不同。我们将不得不重写整个构建配置,这可能会非常耗时,且容易出错。
Rspack
2023 年初,一个新的打包工具加入了竞争:Rspack。它承诺与 webpack 兼容,且具有大幅的性能提升(特别是受益于 Rust 生态)。
虽然我们不喜欢采用全新的技术,但这个承诺太诱人了,所以我们决定在一个冷静期(在季度之间的过渡周,没有既定的 roadmap,便于员工探索新想法)进行尝试。
我们的迁移之旅
实验阶段
由于 Rspack 兼容了 webpack 的大多数配置项,最初的概念验证相当简单。对于不兼容的部分,我们实现了一个小型兼容层,将 webpack 配置项转换为 Rspack 配置。这个兼容层处理了如下问题:
- 移除不必要的 loader(例如
css-loader
)。 - 将一些插件替换为它们在 Rspack 中的等价实现(例如用
rspack.HtmlwebpackPlugin
替换html-webpack-plugin
)。 - 用内置 swc-loader 和压缩器替换我们自定义的 esbuild loader 和压缩器。
因为 Rspack 被设计为 webpack 的替代品,我们仅用了大约 200 行代码就实现了一个兼容层。
这次替换的结果令人印象深刻 ⚡:
- 本地首次构建至多比 webpack 快 3 倍(从 16 秒到 6 秒)
- HMR 至多比 webpack 快 20 倍(从 7 秒到 400 毫秒)
更重要的是,这些数据低估了实际的性能提升,因为:
- 他们比较的是未开启 sourcemaps 的 webpack 和开启了 sourcemaps 的 Rspack(webpack 的 sourcemaps 太慢,以至于我们在开发中默认没有启用)。
- 我们使用了 webpack 的持久化缓存,而 Rspack 未使用缓存。
译者注:Rspack 将在近期提供持久化缓存。
此时,我们遇到了一些问题(当时 Rspack 还处于早期):我们无法让我们的 SSR 配置项正常工作,CSS extract 功能尚未就绪,并且我们遇到了一些短暂的 HMR 异常。
但这整体上已经足够好,让我们决定让工程师在开发中自愿选择使用 Rspack,以观察效果。
上报真实数据
虽然我们已经看到了 Rspack 在本地开发中的优势,但我们希望确保大幅改善开发者体验。
于是我们决定收集构建和 HMR 的数据。这些数据将在开发者的机器上收集,并发送到 Datadog 以便于可视化。
多亏了 Unplugin,我们实现了一个非常简单的插件,该插件同时兼容 webpack 和 Rspack 来完成数据收集。
这使得我们能够确认所有工程师都能受益于这种改进,而不仅仅是在特定场景中。
渐进式迁移
随着 Rspack 从 0.1 版本逐渐改进,并发布到 v1.0 稳定版本,我们也在不断升级和改进我们的配置。
我们开始将小型内部项目迁移到 Rspack。每个项目的迁移过程如下:
- 在本地使用
BUNDLER=rspack
环境变量,选择性地开启 Rspack。 - 将 Rspack 设置为本地默认的打包工具(并允许通过
BUNDLER=webpack
关闭)。 - 切换生产构建到 Rspack。
- 移除对 webpack 的支持。
BUNDLER
环境变量用于收集有关 Rspack 的信息,同时不会对工程师造成限制。将该变量设置为 rspack
会:
- 将开发过程中使用的打包工具切换为 Rspack。
- 在控制台中输出更多信息,帮助工程师(例如,参考我们的内部 Rspack 文档,告诉他们在遇到问题时该联系谁,以及如何切换回 webpack)。
在我们迁移的每个项目中,我们都立即看到了构建时间的改进,并逐步将越来越复杂的代码库迁移到 Rspack。
最终,我们只剩下一个使用 webpack 的项目,即我们的 SSR 登陆页项目(我们正等待 Rspack v1.0,以便能够切换该项目)。
完成迁移
随着时间的推移,我们最初在使用 Rspack 时遇到的所有问题都得到了解决(通过新发布的版本,或是调整我们的配置项)。
Rspack 在上周(2024.09)发布了 第一个稳定版本,我们已经准备好切换最后一个应用。
为了完成迁移,我们:
- 在生产和开发环境中将最后一个应用切换到 Rspack
- 移除兼容层,并使用 Rspack 配置项作为唯一的来源
我们还用 storybook-rsbuild(Rsbuild 是 Rspack 的一个抽象层,与 Storybook 兼容)替换了我们 Storybook 的 webpack5 构建器。
结果
性能
那么,实际的数据表现如何呢?以我们最复杂的项目之一为例,提升是显而易见的:
+---------------------+---------+--------------+
| | webpack | Rspack |
+---------------------+---------+--------------+
| Dev - Initial build | 16.17s | 5.99s (-62%) |
| Dev - HMR | 2.90s | 700ms (-72%) |
| Prod - Build | 2min10s | 34s (-86%) |
+---------------------+---------+--------------+
我们的 Storybook 构建时间从 2 分 25 秒减少到 33 秒 (-88%)。
可维护性
我们还移除了大量的配置项,因为 Rspack 自带了优异的默认配置:
- 我们移除了
css-loader
、style-loader
、resolve-url-loader
和mini-css-extract-plugin
,改用 Rspack 的 experiments.css。 - 我们用内置的
swc-loader
替换了自定义的esbuild-loader
配置。 - 我们移除了
webpack-bundle-analyzer
,改用功能更丰富的 Rsdoctor(兼容 Rspack 和 webpack!) - 在开发过程中,我们也不再需要维护自定义的持久化缓存(有时还得手动清除),因为 Rspack 在无缓存的情况下已经很快了。
內部反馈
团队的反馈非常积极:
切换到 Rspack 对我过去一年多的前端开发来说是非常革命性的变化。
Rspack 让前端开发变得容易多了!
哇塞,那简直太棒了!!! ⚡
展望未来
我们对 Rspack 非常满意,并对打包工具的未来充满期待。我们也在关注 Vite 的动态(特别是即将推出的 Rolldown,它是基于 Rust 的 Rollup 替代品)。
Rspack 的团队还发布了 Rsbuild。这是一个基于 Rspack 的上层构建工具,具有优秀的默认设置,提供了良好的性能和许多开箱即用的功能。
整个生态系统也在快速推进,采用新一代的打包工具。例如,我们依赖 Docusaurus 来进行一些内部文档,迫不及待地想看到他们从 webpack 切换到 Rspack 的完成!
如果你在考虑从 webpack 切换到 Rspack,我们强烈建议你试试看!
转载自:https://juejin.cn/post/7425598941859676170