用 Brotli 与 Gzip 为 Leptos WASM 提速:构建阶段静态压缩的最佳实践

现代Leptos应用依赖WebAssembly (WASM) 来实现丰富的客户端功能。然而,编译后的WASM二进制文件体积可能相当庞大,从而影响加载速度。幸运的是,像Brotli和gzip这样的压缩算法能够显著减小WASM文件体积,实现更快的交付。本文将对比Brotli与gzip在压缩率、解压速度和浏览器支持方面的差异。我将探讨为何压缩Leptos应用中通常较大的WASM资源如此重要——例如,当前网站的944KB的 .wasm​ 文件在使用gzip压缩后减小至约282KB,而使用Brotli压缩后更是降至219KB(体积减小超过75%),极大地提升了下载速度并节省了带宽。我还将阐释为何静态预压缩(在构建时而非实时压缩资源)是处理WASM文件的理想方法:它能减轻服务器CPU负担,生成确定性的文件哈希,并确保一致的性能。最后,Leptos可以通过使用哈希文件名、预压缩文件到配置Axum服务器和Nginx代理,以实现性能调优。

Brotli压缩后的WASM文件大小
Brotli压缩后的WASM文件大小

Brotli vs. Gzip:压缩率、速度与浏览器支持

压缩效果: Gzip和Brotli都采用了相似的底层原理(如LZ77算法和霍夫曼编码),但Brotli通常能实现更高的压缩率。事实上,在最高压缩设置下,对于相同输入,Brotli生成的文件通常比gzip小15-25%。这意味着Brotli能比gzip削减更多文件大小。例如,一个12.4MB的WASM包,用gzip压缩后为4.8MB,而用Brotli压缩后仅为3.5MB——差异显著。实践中,Brotli压缩的内容通常明显更小,尤其对于像WASM这样的文本或二进制格式。文件越小,加载时间就越短,数据消耗也越少(Choosing Between gzip, Brotli and zStandard Compression | Paul Calvano)。

压缩与解压速度: Gzip的deflate算法压缩速度快,而Brotli的高级压缩(尤其在最高级别下)则更消耗CPU,生成最小文件所需时间更长。然而,如果提前进行压缩(正如我稍后讨论的静态预压缩),较慢的压缩速度通常不成问题。另一方面,Brotli和gzip在客户端的解压速度相当——Brotli专为Web设计,其解压速度与gzip几乎一样快。这意味着浏览器可以迅速解压Brotli压缩的内容,因此使用Brotli不会损害客户端性能。总结来说,gzip压缩更快(适用于实时压缩),而Brotli以较慢的压缩速度换取更小的文件体积(这在离线完成时是可接受的)。两种算法在浏览器中的解压速度都非常快(Text Compression in R: brotli, gzip, xz and bz2)。

浏览器支持: Gzip已存在数十年,并得到所有Web客户端的普遍支持。Brotli相对较新(约2015年推出),但现在已被所有主流现代浏览器支持。截至2025年,超过96%的浏览器会发送 Accept-Encoding: br​ 请求头来表明支持Brotli(Caniuse)。换言之,几乎所有使用Chrome、Firefox、Edge、Safari及其他现代浏览器的用户都能接收Brotli压缩的响应。(缺乏Brotli支持的老旧浏览器则会回退到它们都支持的gzip。)重要的是,Brotli广泛的支持和卓越的压缩性能使其极具吸引力——业界专家称其“性能卓越,并且在WebAssembly代码上表现惊人”。总而言之,同时启用Brotli和gzip可确保用户获得其浏览器所能处理的最佳压缩效果。

超过96%的浏览器支持Brotli
超过96%的浏览器支持Brotli

为何要压缩Leptos应用中的WASM资源?

像Leptos这样的Rust框架生成的WASM文件可能非常大(几百KB甚至几MB),因为它们包含了应用的编译代码和数据。通常,整个WASM包必须在应用初始化之前下载完成,因此减小其体积对于快速启动至关重要。好消息是WASM的压缩效果非常好。Leptos官方文档指出,WebAssembly二进制文件“通常压缩效果很好,典型情况下能缩减到未压缩大小的50%以下”。(Optimizing WASM Binary Size)实践中,节省的体积可能更为可观。

例如,当前网站现目前的Leptos应用的发布版本WASM文件未压缩时为944KB(压缩的crate不小心也编译进了WASM)。使用gzip压缩(级别9)后,文件缩小到约282KB;而使用Brotli压缩(质量11)后,进一步缩小到219KB。这意味着体积减少了超过75%——从近1MB降至约0.22MB。这种大幅度的体积缩减显著减少了应用的下载时间和所需带宽。类似地,一个12.4MB的游戏WASM文件,用gzip压缩后降至4.8MB,用Brotli则降至3.5MB。在这两个例子中,压缩都消除了数MB的数据传输。

WASM之所以对压缩响应如此良好,是因为WebAssembly二进制文件包含许多重复的模式和序列,压缩器可以高效地打包它们。通过压缩这些资源,你基本上是“免费”获得了巨大的性能提升(就网络成本而言)——浏览器唯一额外的工作就是解压,而这个过程非常迅速。网速较慢或设备性能较低的用户尤其受益,因为较小的负载能够更快到达。对于交付一个响应迅速、节省带宽的Leptos应用而言,压缩大型WASM文件是必不可少的

静态预压缩:在构建时压缩WASM,而非实时压缩

在提供压缩内容时,你有两种选择:为每个请求实时压缩(动态压缩),或者提前预压缩文件(静态压缩)然后直接提供。对于Leptos中的WASM文件,静态预压缩是理想选择。这意味着你在构建或部署过程中压缩 .wasm​ 文件(及其他资源),并在服务器上存储压缩版本(例如 .wasm.gz​ 和 .wasm.br​ 文件)。然后,Web服务器直接向支持这些格式的客户端提供预压缩文件,而无需实时压缩。

为何对WASM采用预压缩?主要有以下几个好处:

静态预压缩利用了这样一个事实:Brotli的优势在于压缩率,而非速度。我利用构建时间(或CI部署时间)来处理缓慢的压缩步骤,生成极其紧凑的WASM文件,然后让服务器快速交付这些文件。这符合Brotli的预期用例: “Brotli在提供静态内容时最为有效” 。Gzip也可以提前处理以最大化其效益。最终结果是:用户下载的WASM更小,服务器也无需承担运行时成本。

Leptos WASM交付的最佳实践

以下是在Leptos应用中交付WASM(及其他静态资源)的一些最佳实践

哈希化文件名、预压缩资源、为预压缩文件配置服务器、使用正确的缓存头以及正确设置代理——你将确保Leptos应用的WASM负载尽可能高效地交付。用户将因下载文件大幅减小(得益于gzip/Brotli压缩)而享受到更快的加载时间,你的服务器也将因工作负载和带宽使用量的减少而受益。为WASM利用Brotli和gzip是一个简单的步骤,却能带来显著的性能提升,使其成为任何生产Leptos应用不可或缺的优化手段。

你可能也感兴趣