在过去的 15 年里,JavaScript 生态系统迅速扩展,引入了无数工具使开发变得更加容易。但这些工具是有代价的:增加捆绑包的大小。事实上,HTTP Archive 的数据显示,每页平均传输的 JavaScript 量已从 2010 年的 90 KB 激增至 2024 年的 650 KB(来源)。
尽管压缩技术的采用率不断提高并且取得了进步,但这一趋势并没有显示出放缓的迹象。随着我们不断添加功能,挑战仍然存在:我们如何才能减少 JavaScript 的数量?
奇怪的是,解决方案既简单又困难。最简单的部分是项目级别的调整,可以快速取得成果。困难的部分是产生持久的影响,这需要社区范围内的改变来改进捆绑器、库和工具。
本文重点关注您的项目的可行改进,涵盖:
未来的文章将讨论我们可以做出的生态系统范围内的改进,但现在,让我们解决这些因素如何导致捆绑包膨胀 - 以及如何管理它们。
JavaScript 是现代网络交互背后的引擎,但它不是免费的。 JavaScript 是浏览器必须处理的计算成本最高的资源。它通常是决定页面感觉快还是慢的瓶颈,因为臃肿的包会阻止渲染并降低整体性能。
JavaScript 包越大,加载、解析、编译和运行所需的时间就越长。这会延迟其他一切 - 例如显示内容或让用户与页面交互。对于使用具有光纤连接的高端笔记本电脑的人来说,这可能是一个小烦恼。但对于使用低功率手机或不稳定网络的人来说,这可能是完全留在或离开您的网站的区别。
减少 JavaScript 包大小的第一步是 Tree Shaking(或“死代码消除”),大多数捆绑器都是开箱即用的。但所有捆绑商都是平等的吗?
JavaScript 中的捆绑已经取得了长足的进步——从手动串联和任务运行器到复杂的捆绑器。如今,捆绑器性能是一个关键焦点,开发人员优先考虑更快的构建。然而,构建速度并不是一切。同样重要的是它们生成的捆绑包的大小,因为较小的捆绑包意味着用户的加载时间更快。
为了寻求更好的性能,我们已经从使用 JavaScript 编写捆绑器转向 Rust 和 Go 等语言。此切换需要从头开始编写它们,因此旧捆绑器中存在的每个功能和优化都必须重新实现。从长远来看,这可能会得到回报。然而,从短期来看,这意味着它们缺少 JavaScript 捆绑器多年来开发的一些功能,例如良好的 tree shake。这正是可以帮助我们最小化捆绑包大小的功能。
当然,空谈是廉价的,所以让我们看看数字,好吗?
让我们比较八个流行的库,并将它们与七个流行的捆绑器捆绑在一起。为了保持公平,我使用了:
您可以查看基准设置存储库以获取确切的配置。
经过测试的捆绑器:
请注意,在撰写本文时,Rolldown 仍处于 alpha 阶段,因此它处于劣势,随着时间的推移,其结果可能会有所改善。
测试过的库:
这些库的大小和功能各不相同 - 有些库几乎可以像独立应用程序一样运行。
让我们从构建速度开始,因为这是开发人员似乎非常关心的事情。将所有这些库捆绑在一起时,esbuild 是获胜者,其构建时间为 192 毫秒。与最慢的构建时间 7.23 秒相比,快了 37 倍以上。
根据这些结果,我们可以将捆绑器分为三类:
差异非常明显。例如,Rolldown 和 Rspack 分别比旧版本 Rollup 和 webpack 快 11.5 倍和 3.3 倍,同时保持理论上的向后兼容性。切换到这些较新的捆绑器可以显着提高大型项目的生产力。
就输出大小而言,差异并不像构建时间那么大,但它们仍然很重要。
将所有八个库捆绑在一起时,Vite 是获胜者,输出大小为 2087 KiB。与最大输出大小 2576 KiB 相比,输出小了 23.5% 以上。
输出大小的 23.5% 差异是巨大的:在较慢的 3G 连接下,最小的包可能需要大约 5.7 秒才能下载,而最大的包可能需要大约 7 秒。解析和执行时间也会随着包的大小而变化,因此现实世界的差异可能更加明显。
根据这些结果,我们可以将捆绑器输出再次分为三类:
聚合结果并不能描绘出全貌,因为您不太可能在项目中使用上面列出的所有库。更有趣的是这些捆绑器如何处理各个库。
对于像chart.js和mobx这样的库,捆绑器的选择会极大地影响输出大小,差异达到70%。这凸显了使用特定依赖项测试捆绑器的重要性。在大多数其他情况下,差异要小得多,约为 20-30%。
此外,虽然 webpack 总体排名居中,但在 8 个案例中,有 6 个案例表现最好。然而,由于在捆绑handsontable和chart.js时它的表现要差得多,所以它最终还是这样。这意味着,根据您使用的库,webpack 可能是一个不错的选择。
另一方面,我们有 Rolldown。它在 8 个案例中的 7 个中表现最差(请记住,它仍处于 alpha 状态)。
Rspack 也是一个类似的故事。虽然它的性能比 Rolldown 更好,但它仍然生成了比其他捆绑器大得多的捆绑包。
如果您正在考虑迁移到较新的捆绑程序,使用您使用的库进行测试,看看更快的构建速度是否不会以增加输出大小为代价。
如图所示,较新的捆绑器速度更快,但可能会生成更大的捆绑包。从较旧的捆绑程序迁移时,不仅要比较构建时间,还要比较生成的捆绑包大小。您可能会发现自己用更快的构建来换取更大的捆绑包。
例如,在 Angular 从 webpack 切换到 esbuild 后,一些开发人员报告说,空的 Angular 应用程序的大小增加了约 20KB。这完美地突出了构建速度与捆绑包大小的权衡。
这并不是说您不应该关注构建速度,因为它对于开发人员的生产力和幸福感很重要。 CI 构建时间和合并代码所需的时间之间也存在相关性。
选择捆绑器时,首先查看它提供的功能。然后目标是构建速度和包大小之间的平衡。选择可以在您方便的时间内生产尽可能最小的捆绑包的捆绑商。
测试项目中的一些代表性库。如果您的依赖项构成了代码库的大部分,那么您在这些基准测试中看到的差异可以很好地预测您的情况。
我们列表中的下一个是外部库,它们通常构成 JavaScript 包的大部分。在我开发过的许多(如果不是大多数)应用程序中,它们占据了捆绑包大小的大部分。这就是为什么明智地选择(和使用)它们如此重要。
我们中的许多人都安装了 lodash、axios 或 moment 等库,只是为了使用单个功能 - 导致应用程序臃肿。这些库很棒并且具有重要的历史意义,但随着它们变得越来越流行,更轻的替代品被创建,并且它们的一些功能被添加到语言本身中。
我们可以利用这一点。我可以列出这些库的本机 API 或更新且更小的替代方案,但已经有很多文章对此进行了介绍。还有很多其他库,不可能全部涵盖。
这就是为什么我只会给你一个一般性建议,让你看看你使用的库,看看是否可以删除它们或用本机 API 或更小的替代品替换它们。您可能不需要 * 网站是一个很好的入门资源。
默认情况下,大多数库并未针对大小进行优化,但有些库提供特殊的安装路径或部分构建。即使在我们测试的库中,chart.js、handsontable 和 ckeditor5 也提供了一种通过仅包含您需要的部分来减小库大小的方法。让我们以 ckeditor5 为例。
默认安装路径导致捆绑包大小在 660 到 800 KiB 之间。但是,如果我们使用优化的安装路径,捆绑包大小会下降到 603-653 KiB,仅 Rolldown 生成的捆绑包大小约为 750 KiB。大小减少了 7% 到 23%,具体取决于捆绑程序。
另一件事要注意的是重复的依赖关系。这是 JavaScript 应用程序中一个令人惊讶的常见问题。例如,Bluesky 嵌入小部件有两个版本的 zod 验证库。删除重复项使包大小减少了约 9%。
此问题通常不会发生,因为您拉取了同一库的两个不同版本,而是因为您和外部库之一依赖于同一库,但版本不同。这通常可以通过更新您所依赖的库来解决。
考虑到所有这些,我们终于可以进入最后一块拼图 - 您的项目。您可以采取以下措施来缩小捆绑包并提高性能。
第一步是可见性。如果不了解捆绑包中的内容,减小捆绑包的大小就变成了一场猜谜游戏。为此,您可以使用我创建的名为 Sonda 的捆绑分析器和可视化工具。它适用于上述大多数捆绑程序(Parcel 除外),并准确显示参与捆绑的各个文件的大小。
您可以首先将其安装到您的项目中并目视检查捆绑包的各个部分。
一旦您充分了解了捆绑包内的内容并确定了可以优化的部分,您就可以单击图表图块来查看:
Sonda 还会警告您重复的依赖项,以便您可以快速识别并修复问题的根源。
理想情况下,您不仅应该进行一次性检查,还应该将持续监控设置为 CI 管道的一部分。跟踪一段时间内的变化,尤其是在大型项目中,可以帮助您防止小变化随着时间的推移滚雪球般变成严重的膨胀。
最快的代码是您不发送的代码。只要有可能:
如果您无法删除应用程序的某些部分,请尝试代码拆分。代码分割允许您推迟加载应用程序的某些部分,直到需要它们为止,从而缩短初始加载时间。
使用动态 import() 按需加载模块。例如,如果在用户单击按钮之前不需要某个特定功能,则推迟加载该功能直到那一刻。
现代前端框架支持开箱即用的延迟加载,使将代码分割集成到您的工作流程中比以往更容易。
这是一般性建议,但值得重复。遵循最佳实践,例如:
如果您有兴趣让网络更快或只是学习新事物,您应该考虑加入生态系统性能社区。我们专注于三个主要领域:
我希望这篇文章说明您可以用更少的代码提供相同的功能。如果不加以管理,捆绑包大小可能会失控,但即使很小的更改也可以显着提高性能。
从今天开始:分析您的包、测试新工具或替换重量级库。其影响会让你大吃一惊。
我希望您喜欢这篇文章。如果您有任何问题或意见,或者如果您想了解有关特定主题的更多信息,请在下面的评论中告诉我。如果您想了解有关 JavaScript 性能、捆绑和 tree-shaking 主题的更多信息,您可以在此处关注我或在 BlueSky 上关注我并加入 e18e 社区。
以上是缩小 JavaScript 规模:掌握 Bundler 优化的详细内容。更多信息请关注PHP中文网其他相关文章!