缩小应用程序大小
通过 Tauri,我们正在努力减少应用程序对环境的影响,具体做法是在可用的情况下使用更少的系统资源,提供无需运行时评估的编译系统,并提供指南,以便工程师在不牺牲性能或安全性的情况下实现更小的规模。通过节约资源,我们正在尽自己的一份力量帮助您帮助我们拯救地球--这是 21 世纪的公司应该关心的唯一底线。
因此,如果您有兴趣了解如何改进应用程序的大小和性能,请继续阅读!
无法衡量就无法改进
在优化应用之前,您需要弄清楚应用中哪些内容占用了空间!这里有几款工具可以帮助您做到这一点:
-
cargo-bloat
- 一款 Rust 工具,用于确定应用程序中占用空间最大的功能。它能让你对最重要的 Rust 函数进行出色的分类概览。 -
cargo-expand
- 宏使你的 rust 代码更简洁、更易读,但它们也是隐藏的大小陷阱!使用cargo-expand
查看这些宏在引擎盖下生成了什么。 -
rollup-plugin-visualizer
- 这是一款能从您的Rollup 打包中生成漂亮(且有洞察力)图表的工具。非常便于找出哪些 JavaScript 依赖关系对最终打包大小的影响最大。 -
rollup-plugin-graph
- 您注意到最终的前端程序包中包含了一个依赖项,但不确定原因何在? rollup-plugin-graph 可生成与 Graphviz 兼容的整个依赖关系图的可视化效果。
这些只是您可能会用到的几个工具。请务必查看前端打包插件列表,了解更多信息!
清单
精简JavaScript
在典型的 Tauri 应用程序中,JavaScript 占了很大一部分,因此必须使 JavaScript 尽可能轻量级。
您可以从大量 JavaScript 打包程序中进行选择,其中比较流行的有 Vite、webpack 和 rollup。如果配置正确,它们都能生成最小化的 JavaScript,因此请查阅打包程序文档了解具体选项。一般来说,你应该确保:
启用tree shaking
该选项可删除打包中未使用的 JavaScript。所有流行的打包程序都默认启用此选项。
启用最小化
最小化会删除不必要的空白、缩短变量名并进行其他优化。大多数捆绑程序都默认启用了这一功能;rollup 是一个明显的例外,在这种情况下,你需要使用 rollup-plugin-terser 或 rollup-plugin-uglify 等插件。
注意:你可以将 terser 和 esbuild 等缩减器作为独立工具使用。
禁用source maps
在使用编译为 JavaScript 的语言(如 TypeScript)时,source maps可为开发人员带来愉悦的体验。由于source maps往往相当庞大,因此在为生产构建时必须禁用它们。它们对最终用户没有任何益处,因此实际上是无用之物。
优化依赖关系
许多流行的库都有体积更小、速度更快的替代品供您选择。
您使用的大多数库都依赖于许多库本身,因此一个乍看起来不起眼的库可能会为您的应用程序增加几兆字节的代码。
您可以使用 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 的原始图片和你的应用程序一起发送,所以一定要相应地调整图片大小。在屏幕上显示较大的图片,其大小应大于占用屏幕空间较小的图片。
不要使用响应式图片
在网络环境中,您应该使用 响应式图像 为每个用户动态加载正确大小的图像。由于您不是在网络上动态分发图片,因此使用 "响应式图片 "只会让您的应用程序不必要地增加多余的副本。
移除元数据
直接从相机或图片库拍摄的图片通常包含有关相机和镜头型号或摄影师的元数据。这些数据不仅会浪费字节,而且元数据属性还可能包含照片的时间、日期和地点等敏感信息。
删除不必要的自定义字体
考虑不随应用程序提供自定义字体,而是依赖系统字体。如果您必须提供自定义字体,请确保它们采用现代的优化格式,如 woff2
。
字体可能相当大,因此使用操作系统中已包含的字体可以减少应用程序的占用空间。这样还可以避免 FOUT(无样式文本闪烁),并让您的应用程序感觉更 "原生",因为它使用的字体与所有其他应用程序相同。
如果您必须使用自定义字体,请确保使用 woff2 等现代格式,因为这些格式往往比传统格式小得多。
在 CSS 中使用所谓的 "系统字体堆栈"。系统字体堆栈有多种变体,但以下 3 种基本字体堆栈可供参考:
Sans-Serif
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
Serif
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;
Monospace
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation
Mono, monospace;
Allowlist配置
您可以在 allowlist
配置中只启用所需的 Tauri API 功能,从而缩小应用程序的大小。
allowlist
配置决定启用哪些 API 功能;禁用的功能将不会编译到应用程序中。这是一种减轻额外重量的简单方法。
典型的 tauri.conf.json
示例:
{
"tauri": {
"allowlist": {
"all": false,
"fs": {
"writeFile": true
},
"shell": {
"execute": true
},
"dialog": {
"save": true
}
}
}
}
Rust 构建时间优化
配置您的货物项目以利用 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
,并指定除压缩功能外的所有功能,即可禁用压缩功能:
[dependencies]
tauri = { version = "...", features = ["objc-exception", "wry"], default-features = false }
不稳定的Rust压缩功能
以下建议均为不稳定功能,需要使用夜间工具链。如需了解更多相关信息,请参阅 不稳定功能 文档。
以下方法涉及使用不稳定编译器特性,需要使用 rust nightly 工具链。如果没有添加夜间工具链 + rust-src
夜间组件,请尝试以下方法:
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
为了告诉 Cargo 当前项目使用夜间工具链,我们将在项目根目录下创建一个名为 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 -- -Z build-std
如果您在发布配置文件优化中使用 panic = "abort"
,则需要确保 panic_abort
创建 是使用 std 编译的。此外,额外的 std 功能可以进一步缩小二进制文件的大小。以下内容适用于这两种情况:
cargo tauri build --target -- -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(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