减少应用大小
通过 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 Archive,图像对网站重量的贡献最大。因此,如果你的应用包含图像或图标,务必对它们进行优化!
你可以选择各种手动选项(GIMP、Photoshop、Squoosh)或你最喜欢的前端构建工具的插件(vite-imagetools、vite-plugin-imagemin、image-minimizer-webpack-plugin)。
请注意,大多数插件使用的 imagemin
库已 正式停止维护。
使用现代图像格式
与 jpeg 相比,webp
或 avif
等格式可将大小减少 高达 95%,同时保持出色的视觉准确性。你可以使用 Squoosh 等工具在图像上尝试不同的格式。
相应地调整图像大小
没有人希望你在应用中发送 6K 原始图像,因此请务必相应地调整图像大小。在屏幕上显示较大的图像应比占用较少屏幕空间的图像更大。
不要使用响应式图像
在 Web 环境中,你应该使用 响应式图像 为每个用户动态加载正确的图像大小。由于你不会通过网络动态分发图像,因此使用响应式图像只会用冗余副本不必要地增加你的应用大小。
删除元数据
直接从相机或图片网站获取的图像通常包含有关相机和镜头型号或摄影师的元数据。这些不仅是浪费的字节,而且元数据属性还可能包含潜在的敏感信息,例如照片的时间、日期和位置。
移除不必要的自定义字体
考虑不要在你的应用中使用自定义字体,而是依赖系统字体。如果你必须使用自定义字体,请确保它们采用现代的优化格式,例如woff2
。
字体可能非常大,因此使用操作系统中已包含的字体可以减少你的应用的占用空间。它还可以避免 FOUT(未设置样式的文本闪烁),并且由于它使用与所有其他应用相同的字体,因此会让你的应用感觉更“原生”。
如果你必须包含自定义字体,请确保将它们包含在现代格式中,例如woff2
,因为这些格式往往比旧格式小得多。
在你的 CSS 中使用所谓的“系统字体堆栈”。有许多变体,但这里有 3 个基本变体可供你入门
无衬线
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"
有时可能比其他选项小,因此请使用你的应用程序进行测试!
我们已经看到"s"
对于 Tauri 示例应用程序的二进制文件大小较小,但实际应用程序始终可能有所不同。
有关每个选项的详细说明和更多内容,请参阅 Cargo 书籍的 Profiles 部分。
禁用 Tauri 的资产压缩
默认情况下,Tauri 使用 Brotli 压缩最终二进制文件中的资产。Brotli 嵌入了一个大型(~170KiB)查找表以实现出色的效果,但如果嵌入的资源小于此大小或压缩效果不佳,则生成的二进制文件可能大于任何节省。
可以通过将 default-features
设置为 false
并指定除 compression
特性之外的所有内容来禁用压缩
[dependencies]
tauri = { version = "...", features = ["objc-exception", "wry"], default-features = false }
不稳定的 Rust 压缩特性
以下建议都是不稳定的特性,需要 nightly 工具链。有关这方面内容的更多信息,请参阅 不稳定的特性 文档。
以下方法涉及使用不稳定的编译器特性,并需要 nightly Rust 工具链。如果你没有 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
crate 使用 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 target/release/my_application
查看本地strip
手册页以获取更多信息和标志,这些标志可用于指定从二进制文件中剥离哪些信息。
Rust 1.59 现在有一个strip
的内置版本!可以通过将以下内容添加到Cargo.toml
来启用它
[profile.release]
strip = true # Automatically strip symbols from the binary.
UPX
UPX,可执行文件的终极打包器,是二进制打包器中的恐龙。这款维护良好的 23 岁工具包采用 GPL-v2 许可,并带有相当宽松的使用声明。我们对许可的理解是,你可以在任何目的(商业或其他)中使用它,而无需更改你的许可,除非你修改 UPX 的源代码。
也许你的目标受众的互联网非常慢,或者你的应用需要安装在一个小巧的 USB 存储器上,而以上所有步骤都没有达到你需要的节省效果。别担心,因为我们还有最后一个绝招
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