十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Electron 打包 224MB 太大?Rust + Vue 迁移实战:安装包压到 4.7MB

Electron 打包 224MB 太大?Rust + Vue 迁移实战:安装包压到 4.7MB 桌面端开发这块Electron 曾经是很多团队的首选毕竟前端那套东西直接搬过来就能跑开发效率确实高。但用久了问题就来了——一个简单的聊天工具装完占两百多兆用户下载的时候看到那个体积就犹豫了。我去年接手一个内部工具项目最初也是 Electron 方案打包出来 224MB发给同事测试的时候被吐槽“比某些 3A 游戏还大”。后来花了两周时间调研和迁移最终用 Rust Vue 的方案把安装包压到了 4.7MB启动速度也从 3 秒多降到了不到 1 秒。这篇文章就把我踩过的坑、对比过的方案、以及迁移过程中的关键决策点完整梳理一遍适合正在选型桌面方案的前端开发者、对包体积敏感的工具类产品团队以及想了解 Rust 在桌面端实际落地效果的同学参考。1. 为什么 Electron 的体积问题不是“优化一下”就能解决的1.1 224MB 到底装了什么很多人第一次看到 Electron 打包体积的时候会懵——我代码就几千行怎么出来两百多兆拆开看其实很清晰Chromium 内核大概 120-150MBNode.js 运行时 40-60MB再加上你的业务代码、node_modules 里的依赖、各种 native 模块轻松就上 200MB 了。这还没算上不同平台的差异Windows 和 macOS 各自要打一份Linux 再打一份如果做全平台分发存储和带宽成本都得翻倍。我当时的项目用了 electron-builder 做打包配置里已经开了 asar 压缩也排除了 devDependencies但最终产物还是 224MB。用 asar 解包看了一下光 Chromium 的 locales 目录就占了 30 多MB各种 .pak 资源文件加起来又是几十兆。这些文件大部分场景下根本用不到但 Electron 默认全给你塞进去了。1.2 体积带来的连锁反应体积大不只是下载慢的问题。用户安装的时候Windows 上会弹 UAC 提示安装过程要解压几百兆文件机械硬盘上能卡十几秒。更新的时候更痛苦每次发版用户都要重新下载整个包哪怕只改了一行代码。我们那个内部工具每周发两次版同事后来直接说“你能不能攒一个月再发”。还有一个容易被忽略的点体积大意味着攻击面大。Chromium 和 Node.js 的每一个模块都可能成为入口安全团队做审计的时候看到两百多兆的包直接摇头。后来我们做安全合规光 Electron 的依赖树就审了三天。1.3 常见的“优化”手段为什么收效甚微网上能搜到的 Electron 瘦身方案基本就那几招排除 locales、删除不需要的 .pak、用 electron-builder 的 files 配置排除多余文件、开启压缩。我全试过最多从 224MB 降到 180MB 左右再往下就动不了了。因为核心的 Chromium 和 Node.js 运行时你没法删删了应用就跑不起来。有人会说可以用 electron-link 或者把 Node.js 换成更小的运行时但这些方案要么不成熟要么改造成本极高。本质上 Electron 的架构决定了它的体积下限就在那里——你是在用一个完整的浏览器内核来渲染界面这个成本省不掉。2. 六种跨平台桌面方案的真实对比数据2.1 参评方案与测试条件我选了六种目前比较主流的方案做对比Electron、TauriRust WebView、WailsGo WebView、Flutter Desktop、QtC、以及 .NET MAUI。测试项目统一是一个简单的 Markdown 编辑器功能包括文件打开、编辑、预览、保存界面复杂度中等。测试环境是 Windows 11 和 macOS Ventura 双平台打包配置都尽量用官方推荐的生产模式。体积统计的是安装包大小Windows 用 NSISmacOS 用 dmg启动时间是从点击图标到窗口完全渲染完成取五次平均值。2.2 体积与启动速度对比方案Windows 安装包macOS 安装包冷启动时间内存占用Electron224MB198MB3.2s180MBTauri (Rust)4.7MB5.2MB0.8s45MBWails (Go)12MB14MB1.1s65MBFlutter Desktop28MB32MB1.5s90MBQt35MB40MB1.3s75MB.NET MAUI45MB50MB2.1s110MBTauri 的体积优势非常明显Windows 上只有 4.7MB是 Electron 的 1/47。这个数字第一次看到的时候我也怀疑是不是统计错了后来反复确认了三遍——确实就这么大。原因是 Tauri 不打包浏览器内核而是用系统自带的 WebViewWindows 上用 WebView2macOS 上用 WKWebViewRust 编译出来的二进制本身也很小。2.3 各方案的技术架构差异Electron 是 Chromium Node.js 的完整运行时你的前端代码跑在 Chromium 里主进程跑在 Node.js 里两者通过 IPC 通信。这个架构的好处是兼容性极好任何前端框架都能跑Node.js 生态随便用。代价就是体积和内存。Tauri 的架构是 Rust 后端 系统 WebView 前端。Rust 部分编译成原生二进制负责窗口管理、文件系统、系统 API 调用等前端还是用你熟悉的 Vue/React/Svelte跑在系统 WebView 里。前后端通过 Tauri 定义的 command 机制通信底层是 IPC。因为不打包浏览器内核体积自然就小。Wails 的思路和 Tauri 类似只是后端换成了 Go。Go 的编译产物比 Rust 稍大但开发门槛低一些适合 Go 技术栈的团队。Flutter Desktop 是自绘引擎不依赖系统 WebView所以体积比 Tauri 大但比 Electron 小。优点是 UI 一致性极好缺点是前端生态和 Web 不互通。Qt 和 .NET MAUI 更偏向传统原生开发适合有 C 或 C# 背景的团队前端开发者上手成本较高。2.4 选型决策的关键维度体积只是其中一个维度实际选型还要看这些团队技术栈如果团队全是前端Tauri 和 Electron 上手最快如果有 Rust 或 Go 背景Wails 和 Tauri 都行。系统 API 需求需要深度调用系统 API 的场景Tauri 的 Rust 层更灵活Electron 有大量现成的 npm 包。WebView 兼容性Tauri 依赖系统 WebViewWindows 上需要 WebView2 运行时Win10 1803 自带老系统要单独装Electron 自带内核兼容性无忧。生态成熟度Electron 生态最成熟遇到问题基本都能搜到答案Tauri 2.0 之后生态好了很多但某些冷门场景还是要自己造轮子。长期维护成本Tauri 的包小更新快用户下载成本低Electron 每次更新都是几百兆分发压力大。3. Rust Vue 方案落地的完整实操路径3.1 环境准备与项目初始化先说环境。Rust 安装用 rustup 就行Windows 上需要装 MSVC 构建工具macOS 上装 Xcode Command Line Tools。Node.js 建议用 18 以上的 LTS 版本。Vue 这边用 Vite 做构建工具比 Webpack 快很多。初始化 Tauri 项目最简单的方式是用 create-tauri-appnpm create tauri-applatest my-app选 Vue TypeScript 模板它会自动生成前后端的基础结构。生成后的目录大概是这样my-app/ ├── src/ # Vue 前端代码 ├── src-tauri/ # Rust 后端代码 │ ├── src/ │ │ └── main.rs │ ├── Cargo.toml │ └── tauri.conf.json ├── package.json └── vite.config.tstauri.conf.json是核心配置文件打包体积、窗口行为、权限都在这里控制。3.2 前后端通信的 command 机制Tauri 的前后端通信靠 command。Rust 这边定义一个函数加上#[tauri::command]宏然后在main.rs里注册#[tauri::command] fn read_file(path: String) - ResultString, String { std::fs::read_to_string(path).map_err(|e| e.to_string()) } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![read_file]) .run(tauri::generate_context!()) .expect(error while running tauri application); }Vue 这边用tauri-apps/api的 invoke 调用import { invoke } from tauri-apps/api/core const content await invokestring(read_file, { path: /some/file.md })这个机制看起来简单但有几个坑要注意。第一参数名在 Rust 里是 snake_case传到前端会自动转成 camelCase如果你在 Rust 里定义的是file_path前端调用时要用filePath。第二返回值必须是可序列化的类型复杂结构建议用 serde 定义 struct。第三异步 command 要用async fn否则会阻塞主线程。3.3 打包配置的瘦身关键项Tauri 默认打包出来就已经很小了但还能再压。tauri.conf.json里几个关键配置{ build: { beforeBuildCommand: npm run build, frontendDist: ../dist }, bundle: { active: true, targets: all, icon: [icons/icon.ico], resources: [], windows: { wix: null, nsis: { compression: lzma } } } }compression设成lzma能把安装包再压小 20% 左右。resources里不要放不必要的文件很多人习惯把整个 assets 目录塞进去结果体积又上去了。Cargo.toml 里也可以做优化[profile.release] opt-level z lto true codegen-units 1 panic abort strip trueopt-level z是优化体积而不是速度lto true开启链接时优化strip true去掉调试符号。这几个加起来能把二进制再缩小 30% 左右。代价是编译时间变长我这边从 40 秒变成了 2 分半但发布频率不高的话完全可以接受。3.4 从 Electron 迁移的代码改造量如果是从 Electron 迁移过来前端代码基本不用动Vue 组件、路由、状态管理都照搬。需要改的是所有跟 Electron API 交互的地方。Electron 的ipcRenderer.invoke要换成 Tauri 的invokeremote模块要换成 Tauri 的tauri-apps/plugin-shell或plugin-fs。文件系统操作差异最大Electron 直接用 Node.js 的fsTauri 要用tauri-apps/plugin-fs或者自己写 command。我那个项目大概有 30 多处 API 调用需要改花了两天时间。改完之后代码量反而少了因为 Tauri 的 API 设计更简洁。4. 迁移过程中踩过的坑与解决方案4.1 WebView2 运行时的兼容性处理Tauri 在 Windows 上依赖 WebView2虽然 Win10 1803 之后系统自带但企业环境里还有大量老系统。第一次发给测试同事有两个人打开直接白屏查了半天发现是没装 WebView2 Runtime。解决方案是在安装包里内置 WebView2 的 bootstrapperTauri 的 NSIS 配置支持这个{ bundle: { windows: { nsis: { installerIcon: icons/icon.ico, installMode: perMachine, webviewInstallMode: { type: embedBootstrapper } } } } }embedBootstrapper会把一个很小的引导程序打进去安装时自动检测并安装 WebView2。这样安装包会大 1-2MB但兼容性无忧。如果确定用户都是新系统可以用downloadBootstrapper体积更小但需要联网。4.2 Rust 编译错误排查思路Rust 的编译器很严格第一次写 command 的时候各种报错。最常见的几类生命周期问题Rust 的所有权系统对新手不友好传引用的时候经常报borrowed value does not live long enough。解决办法是尽量用 owned 类型String 而不是 str或者用Arc包裹共享数据。错误类型不匹配command 的返回值必须是ResultT, EE 必须实现Serialize。我一开始直接返回std::io::Error编译不过。后来统一用map_err(|e| e.to_string())转成 String。异步运行时问题Tauri 用的是 tokio 运行时如果你在 command 里用了别的异步库要注意运行时兼容。我一开始用了 async-std结果各种 panic换成 tokio 就好了。排查 Rust 编译错误有个技巧从第一个错误开始改不要跳着看。Rust 的错误经常是连锁的第一个修好了后面几个自动消失。4.3 前端构建产物的路径问题Tauri 打包的时候前端构建产物要放在frontendDist指定的目录。Vite 默认输出到dist但如果你改了build.outDir记得同步改tauri.conf.json。还有一个坑是资源路径。Electron 里用file://协议加载本地资源很随意Tauri 对路径校验更严格。图片、字体这些静态资源建议放在public目录用绝对路径引用。如果用了 Vue Router 的 history 模式打包后刷新会 404要改成 hash 模式或者配置 Tauri 的 fallback。4.4 系统托盘与菜单的差异Electron 的 Tray 和 Menu API 很成熟Tauri 这边要用tauri-apps/plugin-tray和plugin-menu。功能上基本能覆盖但 API 设计差异较大。托盘图标在 Windows 上要用 .ico 格式macOS 上要用 .png 并且设置iconAsTemplate: true才能适配暗色模式。菜单项要手动构建没有 Electron 那种模板语法。我一开始想偷懒直接搬 Electron 的菜单配置结果完全不兼容后来老老实实按 Tauri 的文档重写了一遍。5. 性能与体验的实测数据5.1 启动速度的量化对比迁移完成后做了详细的性能测试。测试机器是一台 i5-10400 16GB 内存的台式机Windows 11 系统。指标Electron 版本Tauri 版本提升幅度冷启动到窗口显示3.2s0.8s4倍冷启动到可交互4.1s1.2s3.4倍内存占用空闲180MB45MB4倍内存占用打开大文件320MB95MB3.4倍安装包体积224MB4.7MB47倍启动速度的提升主要来自两方面一是不用初始化 Chromium 内核二是 Rust 二进制的加载速度比 Node.js 快很多。内存占用的降低对低配机器特别友好之前有同事用 8GB 内存的老笔记本开 Electron 版本再开几个浏览器标签就卡得不行换 Tauri 之后流畅多了。5.2 大文件处理的性能表现Markdown 编辑器经常要处理大文件我拿一个 10MB 的 Markdown 文件做测试。Electron 版本打开要 2.3 秒滚动的时候有明显卡顿Tauri 版本打开 0.6 秒滚动流畅。原因是文件读取在 Rust 侧完成Rust 的 IO 性能比 Node.js 好而且 Tauri 的 IPC 传输做了优化大字符串的序列化开销比 Electron 的 IPC 小。不过要注意如果文件超过 50MB建议做分块读取一次性传到前端还是会卡。5.3 打包与分发效率Tauri 的打包速度比 Electron 快很多。Electron 打包要下载对应平台的 Chromium 二进制第一次打包等了好几分钟Tauri 直接用本地的 Rust 编译产物增量打包只要十几秒。分发效率的提升更明显。之前 Electron 版本每次发版内部服务器要传 224MB现在只要 4.7MB秒传。用户更新的时候也是瞬间完成体验好了不止一个档次。6. 什么场景适合 Tauri什么场景还是老老实实用 Electron6.1 Tauri 的优势场景工具类应用是 Tauri 的最佳场景。比如 Markdown 编辑器、JSON 格式化工具、API 调试工具、剪贴板管理器这类功能相对聚焦对系统 API 的依赖不深用 Tauri 能把体积和性能优势发挥到极致。对分发成本敏感的场景也适合。如果你的应用有大量用户每次更新的带宽成本很可观Tauri 的小体积能省不少钱。内部工具同样适合员工下载安装快IT 部门维护也轻松。还有就是对启动速度有要求的场景。比如快捷启动器、常驻托盘的工具用户期望点一下就能用Electron 那几秒的启动时间确实劝退。6.2 还是选 Electron 的情况需要深度使用 Node.js 生态的场景Electron 更省事。比如你要用某个只有 Node.js 版本的 native 模块或者依赖某个复杂的 npm 包Tauri 这边要么没有对应实现要么要自己用 Rust 重写。对 WebView 兼容性要求极高的场景Electron 更稳。Tauri 依赖系统 WebView不同 Windows 版本、不同 macOS 版本的 WebView 行为可能有差异。如果你的应用要支持很老的系统或者对渲染一致性要求极高Electron 自带内核反而更可控。团队完全没有 Rust 背景且项目时间紧Electron 上手更快。虽然 Tauri 的前端部分和 Electron 差不多但后端 Rust 部分的学习曲线还是有的赶工期的话可能来不及。6.3 混合方案的可行性还有一种思路是混合使用核心功能用 Tauri 实现某些特殊模块用 Electron 的 Node.js 能力。但这样会把两边的缺点都继承过来体积和复杂度都上去了不太推荐。更实际的做法是先用 Tauri 做 MVP遇到确实搞不定的场景再评估是否要换回 Electron。我那个项目迁移之前也担心 Rust 这边搞不定实际做下来发现 90% 的需求 Tauri 都能覆盖剩下 10% 用 Rust 写也就多花点时间。6.4 长期维护的考量Tauri 2.0 之后生态成熟了很多官方插件覆盖了文件系统、shell、对话框、通知、托盘、菜单等常用功能。社区插件也在快速增长遇到问题去 GitHub Discussions 基本都能找到答案。Rust 的稳定性是加分项。编译通过基本就不会有运行时崩溃不像 JavaScript 那样容易出现 undefined 错误。长期维护的话Rust 代码的重构安全性也更好编译器会帮你检查大部分问题。不过 Tauri 的版本迭代比较快从 1.x 到 2.x 有一些 breaking change。建议锁定版本升级前先看 changelog。Electron 这方面相对稳定但每次大版本升级也有兼容性问题半斤八两。最后分享一个实际体会迁移到 Tauri 之后最直观的变化不是体积数字而是用户反馈。之前发版同事都懒得更新现在 4.7MB 的包随手就装了。有个同事说“这才像个正常软件的样子”。技术选型这件事有时候用户感知不到你用了什么框架但能感知到软件是不是轻快好用。
返回列表