减小应用大小
在 Tauri 中,我们致力于通过在可用情况下减少系统资源的使用、提供无需运行时评估的编译系统以及提供指南来帮助工程师在不牺牲性能或安全性的前提下进一步减小应用体积,从而减少应用程序的环境足迹。通过节省资源,我们正在尽自己的一份力量来帮助您保护地球——这是 21 世纪公司唯一应该关心的底线。
因此,如果您有兴趣学习如何改进您的应用大小和性能,请继续阅读!
无法衡量的东西无法改进
在优化您的应用之前,您需要弄清楚是什么占用了您的应用空间!以下是一些可以帮助您的工具
cargo-bloat
- 一个 Rust 实用程序,用于确定什么在您的应用中占用了最大空间。它为您提供了最重要的 Rust 函数的优秀排序概述。cargo-expand
- 宏 使您的 Rust 代码更简洁易读,但它们也是隐藏的大小陷阱!使用cargo-expand
来查看这些宏在幕后生成的代码。rollup-plugin-visualizer
- 一个工具,可以根据您的 rollup 包生成精美(且富有洞察力)的图表。对于确定哪些 JavaScript 依赖项对最终包大小的贡献最大非常方便。rollup-plugin-graph
- 您注意到最终前端包中包含了一个依赖项,但不确定原因?rollup-plugin-graph
生成与 Graphviz 兼容的整个依赖关系图的可视化。
这些只是您可以使用的一些工具。请务必检查您的前端打包程序插件列表以了解更多信息!
清单
压缩 JavaScript
JavaScript 构成了典型 Tauri 应用的很大一部分,因此使 JavaScript 尽可能轻量级非常重要。
您可以选择大量的 JavaScript 打包器;流行的选择包括 Vite、webpack 和 rollup。如果正确配置,所有这些都可以生成压缩的 JavaScript,因此请查阅您的打包器文档以了解具体的选项。一般来说,您应该确保:
启用 tree shaking
此选项会从您的包中移除未使用的 JavaScript。所有流行的打包器都默认启用此功能。
启用压缩
压缩会移除不必要的空格、缩短变量名并应用其他优化。大多数打包器默认启用此功能;一个值得注意的例外是 rollup,您需要使用诸如 rollup-plugin-terser 或 rollup-plugin-uglify 之类的插件。
注意:您可以使用诸如 terser 和 esbuild 之类的压缩器作为独立工具。
禁用源映射
源映射在使用编译为 JavaScript 的语言(例如 TypeScript)时提供了良好的开发体验。由于源映射往往相当大,因此在构建生产版本时必须禁用它们。它们对您的最终用户没有好处,因此实际上是无效的负担。
优化依赖项
许多流行的库都有更小、更快的替代方案可供选择。
您使用的许多库本身都依赖于许多库,因此乍一看不起眼的库可能会向您的应用添加几兆字节的代码。
您可以使用 Bundlephobia 来查找 JavaScript 依赖项的成本。由于编译器进行了许多优化,因此检查 Rust 依赖项的成本通常比较困难。
如果您发现某个库显得过大,请在 Google 上搜索一下,很可能其他人已经想到了这一点并创建了替代方案。一个很好的例子是 Moment.js 及其 许多替代方案。
但是请记住:最好的依赖项是没有依赖项,这意味着您应该始终优先选择语言内置函数而不是第三方包。
优化图像
根据 HTTP 档案,图像是 网站大小的最大贡献者。因此,如果您的应用包含图像或图标,请确保优化它们!
您可以选择各种手动选项(GIMP、Photoshop、Squoosh)或您最喜欢的前端构建工具的插件(vite-imagetools、vite-plugin-imagemin、image-minimizer-webpack-plugin)。
请注意,大多数插件使用的imagemin
库 官方已不再维护。
使用现代图像格式
与 jpeg 相比,webp
或 avif
等格式可以将大小减少高达 95%,同时保持出色的视觉精度。您可以使用诸如 Squoosh 之类的工具来尝试不同格式的图像。
相应地调整图像大小
没有人欣赏您将 6K 原图与您的应用一起发布,因此请确保相应地调整图像大小。在屏幕上显示较大的图像应比占用较少屏幕空间的图像尺寸更大。
不要使用响应式图像
在 Web 环境中,您应该使用 响应式图像 来动态加载每个用户的正确图像大小。由于您不是在 Web 上动态分发图像,因此使用响应式图像只会不必要地用冗余副本膨胀您的应用。
移除元数据
直接从相机或库存照片网站拍摄的图像通常包含有关相机和镜头型号或摄影师的元数据。这些不仅是浪费字节,元数据属性还可能包含可能敏感的信息,例如照片的时间、日期和位置。
移除不必要的自定义字体
建议不要在应用中打包自定义字体,而是使用系统字体。如果必须使用自定义字体,请确保它们采用现代化的优化格式,例如woff2
。
字体文件可能很大,使用操作系统自带的字体可以减小应用的体积。它还可以避免 FOUT(未样式化文本闪现)问题,并使您的应用感觉更“原生”,因为它与其他所有应用使用相同的字体。
如果必须包含自定义字体,请确保使用现代格式,例如woff2
,因为这些格式通常比传统格式小得多。
在 CSS 中使用所谓的“系统字体栈”。虽然有很多变体,但这里有三个基本的示例可以帮助您入门
无衬线字体
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
衬线字体
font-family: Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid
Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe
UI Symbol;
等宽字体
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation
Mono, monospace;
允许列表配置
您可以通过仅在allowlist
配置中启用所需的 Tauri API 功能来减小应用的体积。
allowlist
配置决定了要启用的 API 功能;禁用的功能将不会编译到您的应用中。这是一种轻松减轻应用体积的简单方法。
一个典型的tauri.conf.json
示例
{
"tauri": {
"allowlist": {
"all": false,
"fs": {
"writeFile": true
},
"shell": {
"execute": true
},
"dialog": {
"save": true
}
}
}
}
Rust 编译时优化
配置您的 Cargo 项目以利用 Rust 的大小优化功能。为什么 Rust 可执行文件这么大? 提供了对此问题的出色解释和深入的演练。同时,最小化 Rust 二进制文件大小 更加新颖,并提供了一些额外的建议。
Rust 以生成大型二进制文件而闻名,但您可以指示编译器优化最终可执行文件的大小。
Cargo 提供了几个选项来确定编译器如何生成您的二进制文件。对于 Tauri 应用,推荐的选项如下:
[profile.release]
panic = "abort" # Strip expensive panic clean-up logic
codegen-units = 1 # Compile crates one after another so the compiler can optimize better
lto = true # Enables link to optimizations
opt-level = "s" # Optimize for binary size
strip = true # Remove debug symbols
还可以使用opt-level = "z"
来减小生成的二进制文件大小。"s"
和 "z"
有时可能比其他选项更小,因此请在您的应用程序中进行测试!
我们在 Tauri 示例应用程序中看到了使用 "s"
获得更小的二进制文件大小,但实际应用程序可能会有所不同。
有关每个选项的详细说明以及更多信息,请参阅Cargo 手册的配置文件部分。
禁用 Tauri 的资源压缩
默认情况下,Tauri 使用 Brotli 压缩最终二进制文件中的资源。Brotli 内嵌一个大型(约 170KiB)的查找表以实现最佳效果,但是,如果嵌入的资源小于此大小或压缩效果较差,则生成的二进制文件可能会比节省的大小更大。
可以通过将default-features
设置为false
并指定除compression
功能之外的所有功能来禁用压缩
[dependencies]
tauri = { version = "...", features = ["objc-exception", "wry"], default-features = false }
不稳定的 Rust 压缩功能
以下建议都是不稳定的功能,需要 nightly 工具链。有关此操作的更多信息,请参阅不稳定功能 文档。
以下方法涉及使用不稳定的编译器功能,需要 rust nightly 工具链。如果您没有 nightly 工具链 + 已添加rust-src
nightly 组件,请尝试以下操作:
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
要告诉 Cargo 当前项目使用 nightly 工具链,我们将在项目的根目录创建一个覆盖文件,名为rust-toolchain.toml
。此文件将包含以下内容:
[toolchain]
channel = "nightly-2023-01-03" # The nightly release to use, you can update this to the most recent one if you want
profile = "minimal"
Rust 标准库是预编译的。这意味着 Rust 安装速度更快,但也意味着编译器无法优化标准库。您可以使用不稳定的标志将其余二进制文件 + 依赖项的优化选项应用于 std。此标志需要指定您的目标,因此请了解您所针对的目标三元组。
cargo tauri build --target <Target triple to build for> -- -Z build-std
如果您在发布配置文件优化中使用panic = "abort"
,则需要确保panic_abort
库已使用 std 编译。此外,额外的 std 功能可以进一步减小二进制文件大小。以下内容适用于两者:
cargo tauri build --target <Target triple to build for> -- -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort
有关-Z build-std
和-Z build-std-features
的更多详细信息,请参阅不稳定文档。
剥离
使用 strip 实用程序删除已编译应用中的调试符号。
已编译的应用包含所谓的“调试符号”,其中包含函数和变量名称。您的最终用户可能并不关心调试符号,因此这是一个非常可靠的节省字节的方法!
最简单的方法是使用著名的strip
实用程序删除这些调试信息。
strip target/release/my_application
有关更多信息以及可用于指定从二进制文件中删除哪些信息的标志,请参阅您本地的strip
手册页。
Rust 1.59 现在内置了strip
版本!可以通过将以下内容添加到您的Cargo.toml
中来启用它:
[profile.release]
strip = true # Automatically strip symbols from the binary.
UPX
UPX(Ultimate Packer for eXecutables)是二进制打包程序中的老前辈。这款已有 23 年历史、维护良好的工具采用 GPL-v2 许可,具有相当宽松的使用声明。我们对许可的理解是,您可以将其用于任何目的(商业或其他目的),无需更改您的许可证,除非您修改 UPX 的源代码。
也许您的目标受众互联网速度非常慢,或者您的应用需要安装在非常小的 U 盘上,而上述所有步骤都没有带来您所需的节省。别担心,我们还有最后一招
UPX 会压缩您的二进制文件并创建一个自解压的可执行文件,该文件会在运行时自行解压。
您应该知道,此技术可能会将您的二进制文件标记为 Windows 和 macOS 上的病毒 - 因此请自行决定使用它,并且像往常一样,请使用Frida 进行验证并进行真实的发布测试!
在 macOS 上的使用
brew install upx
yarn tauri build
upx --ultra-brute src-tauri/target/release/bundle/macos/app.app/Contents/macOS/app
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2018
UPX 3.95 Markus Oberhumer, Laszlo Molnar & John Reiser Aug 26th 2018
File size Ratio Format Name
-------------------- ------ ----------- -----------
963140 -> 274448 28.50% macho/amd64 app