背景
自主研发了一款面向个人用户的时间管理系统,核心功能涵盖任务管理、番茄钟计时、日志记录等;该系统主要以 Web 应用形态提供给用户,同时配套提供微信小程序、安卓及鸿蒙端应用,作为时空上便利性的补充。
近期收到用户反馈,希望能推出 Windows 桌面端应用 ------ 核心诉求是解决浏览器使用时易误关闭且谷歌浏览器内存占用过高的问题。
技术选型
从技术选型角度来看,基于.NET 原生开发 Windows 桌面应用虽能实现最优性能与最佳用户体验,但需重新开发大量前端页面及逻辑,开发成本与时间成本过高,显然不具备可行性。因此,我将目光转向了 "Web 套壳" 类技术方案。
首先想到的是业内主流的 Electron 框架,不过回溯过往经验:约 2-3 年前我曾尝试过一款基于 Electron+Vue 的二次封装框架,在部署环节出现报错,且错误信息指向模糊,文档又过于简略,排查与解决难度极大,最终不得不放弃该方案。尽管 Electron 是生态成熟的主流选择(典型案例如 VS Code),但其安装包体积庞大、运行时性能与内存消耗偏高的问题一直饱受诟病,也与期望的 "降低内存占用" 的核心诉求相悖。
于是问了下 AI,当前有哪些技术方案可选,AI 给了几种方案,并做了对比,如下:
| 方案 | 开发成本 | 包体积 | 性能 | 跨平台 | 生态 | 适用场景 |
|---|---|---|---|---|---|---|
| Electron | 极低 | 大(80+MB) | 中等 | 全平台 | 极丰富 | 前端主导、中大型 Web 套壳 |
| Tauri | 低 - 中 | 极小(2-8MB) | 优秀 | 全平台 | 中等 | 轻量应用、追求性能 / 体积 |
| NW.js | 极低 | 大80+MB) | 中等 | 全平台 | 中等 | 老项目迁移、极简套壳 |
| 原生 WebView | 极高 | 极小(1-3MB) | 最优 | 单平台 | 原生生态 | 极致性能、有原生开发团队 |
| Flutter+WebView | 中 - 高 | 中(20-30MB) | 良好 | 全平台 | 中等 | 需跨移动端 + 桌面端、混合 UI |
同时,给出的选型核心原则如下:
- 优先选 Electron:无原生开发资源、追求开发效率、需丰富桌面特性;
- 选 Tauri:对体积 / 性能敏感、轻量应用、可接受少量 Rust 学习成本;
- 选原生 WebView:有 C#/Swift 开发团队、极致性能需求、仅需单平台;
- 选 Flutter:需同时支持移动端(iOS/Android)+ 桌面端。
Electron、WebView 和Flutter 这些上面提过了为什么不选的原因,Tauri 引起了我的兴趣,因此做了进一步了解,AI 介绍如下:
一、Tauri 核心定义
Tauri 是一款跨平台轻量级桌面应用开发框架,由 Rust 编写核心层,主打 "将 Web 前端代码打包为原生桌面应用",支持 Windows、macOS、Linux 三大桌面平台。它诞生的核心目标是解决 Electron 体积庞大、内存占用高的痛点,同时保留 "复用 Web 技术栈" 的低开发成本优势,是 Electron 最主流的轻量化替代方案。
二、Tauri 核心特性
- 极致轻量化(核心优势)
体积:打包后的 Windows 安装包仅 5MB 左右(Electron 通常 50MB+);
内存占用:运行时内存消耗仅为 Electron 的 40% 左右,远低于 Chrome 浏览器,完美解决用户反馈的 "谷歌浏览器占内存偏大" 问题;
轻量化根源:复用系统原生 WebView(Windows 用 Edge WebView2、macOS 用 WebKit、Linux 用 WebKitGTK),而非像 Electron 那样内置完整的 Chromium 浏览器内核。- 低开发成本,复用现有 Web 代码
对你的时间管理系统而言,无需重构任何已有的 Web 前端逻辑:
完全兼容 HTML/CSS/JS/Vue/React 等主流 Web 技术栈;
仅需配置 Tauri 指向你的 Web 应用地址(本地 / 远程均可),即可快速打包为桌面应用;
前端与原生层的交互简单,支持 IPC(进程间通信)双向调用,如需扩展桌面原生能力(如托盘、快捷键),仅需少量 Rust 代码补充。- 安全可靠
核心层基于 Rust 开发,天然具备内存安全特性,避免了 Electron/Node.js 常见的权限漏洞;
内置严格的 CSP(内容安全策略),可细粒度控制 Web 资源加载权限;
原生 API 调用需显式配置权限,降低安全风险。- 原生桌面体验
支持原生窗口定制(大小、缩放、全屏、最小化到托盘等),解决 "浏览器不小心关掉" 的问题;
可调用 Windows 系统级 API(如通知、文件读写、快捷键),体验与原生 .NET 应用几乎无差;
打包格式支持 Windows 主流的 exe、msi 安装包,符合用户使用习惯。三、Tauri 适配你的时间管理系统的核心优势
精准解决用户痛点:既避免了浏览器误关问题,又大幅降低内存占用,完全匹配用户对 Windows 桌面端的核心诉求;
开发成本可控:无需像 .NET 原生开发那样重构前端逻辑,仅需 1-2 小时即可完成基础套壳和打包;
未来扩展性强:若后续需要扩展 macOS/Linux 桌面端,仅需修改少量配置即可跨平台打包;
体验接近原生:支持托盘、系统通知、快捷键等桌面特性,比单纯的浏览器窗口体验更优。
综合考虑,是替代Electron 的最优方案,于是决定就用Tauri 框架了。
集成与封装
虽说选了轻量的 Tauri 来封装桌面应用,但它底层是 Rust 写的 ------ 我对 Rust 基本没啥了解,语法和运行机制都摸不着头脑,心里多少有点没底。
我打开字节的 AI 编程工具 TRAE,切到 SOLO 模式,把 "用 Tauri 把 Web 应用打包成桌面端" 的需求丢给它,AI 立马开工,弹出来一堆要安装的组件,连 Rust 都在列表里,安装过程就俩字:折腾,这里就不多啰嗦了。
卡壳的地方是构建环境:AI 反复提示需要 VC++ 编译器,但它给的操作步骤试了好几次都翻车,我跟着手动操作也没用。最后还是翻出 Visual Studio 的安装包,自己把相关依赖项都勾上装好,这才把环境捋顺,光这儿就耗了不少时间。
环境搞定后打包倒是顺利,结果一运行就傻了 ------ 连不上后端。喊 AI 帮忙查问题,折腾来折腾去也没解决。我琢磨了下原因:之前 Web 版是用 Nginx 当应用服务器,接口写的都是相对路径 "pro",靠 Nginx 的路由规则转发到后端;但桌面端没了 Nginx 反向代理,得把后端的完整域名 + 路径写全才行。手动调整路径再测试,这问题才算搞定。
前前后后折腾了 1 天,基础的封装总算是跑通了,本以为能松口气,没想到这才是 "欲哭无泪" 的折腾起点......
问题与解决
运行环境判断
我们开发的应用需要同时兼容 Web 浏览器 与 Tauri 客户端 双端运行环境,部分功能需根据运行载体做差异化实现 ------ 比如番茄钟计时结束的消息通知,Web 端可直接调用浏览器 Notification API 完成推送,而客户端则需要对接操作系统原生通知接口。因此,精准判断当前运行环境,就成了双端功能适配的首要前提。
看似简单的需求,却因 Tauri 版本迭代和网络上的 AI 误导性方案,踩了不少坑。最典型的就是通过判断 window.__TAURI__是否存在来区分环境的方法,这种方案仅适用于 Tauri 1.x 版本;升级到 Tauri 2.x 后,该全局变量被移除,原有判断逻辑彻底失效。
AI 又建议调用官方插件tauri-plugin-os,使用其 platform 方法,如下图:
powershell
async function isClientEnvironment() {
const { platform } = await import('@tauri-apps/plugin-os')
const currentPlatform = platform()
return (
currentPlatform.includes('windows') ||
currentPlatform.includes('macos') ||
currentPlatform.includes('linux')
)
}
但新的问题接踵而至:在纯 Web 运行环境下,直接引用 Tauri 插件的代码会直接抛出报错 ------ 这意味着我们本想通过 Tauri 插件做环境判断,却必须先通过 "动态导入" 的方式规避 Web 端的插件引用报错;可动态导入的前提,又是我们已经明确知道当前是 Tauri 客户端环境。
这就陷入了"先有鸡还是先有蛋" 的逻辑死循环:要判断客户端环境就得用插件,要用插件又得先确定是客户端环境才能动态导入,两者互为前提,完全不具备实操性。
无奈之下,我们彻底放弃了各类 AI 生成的 "标准答案",转而回归最传统的解决方式:通过百度检索 + 人工排查,最终在Tauri 官方仓库的 GitHub Issue 找到了一条极简且可行的方案 ------ 判断全局变量 window.TAURI_INTERNALS 是否非空。
这个变量是 Tauri 2.x 版本会自动注入到全局的环境标识,却并未出现在任何官方文档中,完全是藏在社区讨论里的 "隐藏方案";而正是这个未公开的全局变量,打破了此前的逻辑死循环:无需依赖任何插件,仅通过这个原生注入的变量就能精准区分 Tauri 2.x 客户端与纯 Web 环境,彻底解决了双端环境判断的核心痛点。
实现托盘功能
另一处耗时良久的踩坑点,是 TRAE 项目基于 Tauri 2.9.5 版本实现「点击窗口关闭按钮,将应用最小化到系统托盘」的功能 ------ 这个看似基础的需求,却走了大段弯路。
最初基于 Tauri 2.9.5 版本反复调试,尝试了社区零散的方案和 AI 生成的代码示例,折腾了好长时间始终无法实现核心逻辑。排查无果后,AI 得出了「Tauri 最新 2.x 版本砍掉了托盘最小化功能,必须降级到 1.x 版本才能用」的结论。
可实际将版本回退到 Tauri 1.x 后,这个功能依然无法正常生效 ------问题根本不在于版本迭代,而是 AI 不清楚应该怎么做。
于是彻底 弃用了 AI,从头系统研读 Tauri 官方文档,结合项目场景一点点调试验证。最终发现,此前的失败并非版本不支持,最终实现了 "关闭窗口不退出、最小化到托盘" 的功能,其中关键的一句 api.prevent_close(),在 AI 的认知之外。
powershell
// 使用 Tauri 2.0 正确 API 实现所有功能
use tauri::{
menu::{MenuBuilder, MenuItemBuilder},
tray::{TrayIconBuilder, TrayIconEvent},
Manager,
};
use tauri_plugin_single_instance::init as single_instance_init;
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_notification::init())
.setup(|app| {
// 1. 初始化单实例插件
app.handle()
.plugin(single_instance_init(|app, _argv, _cwd| {
// 当新实例启动时,激活现有实例的窗口
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}))?;
// 2. 获取主窗口
let main_window = match app.get_webview_window("main") {
Some(window) => window,
None => {
eprintln!("主窗口(ID: main)未创建!");
return Ok(());
}
};
// 3. 监听窗口关闭事件
let window_clone = main_window.clone();
main_window.on_window_event(move |event| {
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
// 阻止默认关闭
api.prevent_close();
// 隐藏窗口
let _ = window_clone.hide();
}
});
// 4. 创建托盘菜单
let show_window_item = MenuItemBuilder::new("显示主窗口")
.id("show_window")
.build(app)?;
let quit_app_item = MenuItemBuilder::new("退出应用").id("quit_app").build(app)?;
let tray_menu = MenuBuilder::new(app)
.item(&show_window_item)
.item(&quit_app_item)
.build()?;
// 5. 创建系统托盘
let _tray = TrayIconBuilder::new()
.icon(app.default_window_icon().unwrap().clone())
.tooltip("时光助手")
.menu(&tray_menu)
// 处理托盘双击事件
.on_tray_icon_event(|tray, event| {
if let TrayIconEvent::DoubleClick { .. } = event {
let app_handle = tray.app_handle();
// 获取窗口并显示
if let Some(window) = app_handle.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
})
// 处理菜单点击事件
.on_menu_event(|tray, event| {
let app_handle = tray.app_handle();
match event.id().as_ref() {
"show_window" => {
if let Some(window) = app_handle.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
"quit_app" => {
// 退出应用
app_handle.exit(0);
}
_ => {}
}
})
.build(app)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("运行 Tauri 应用失败");
}
实现单例运行
在解决了环境判断和托盘最小化的问题后,另一个核心需求是保证客户端程序的单一实例运行------ 避免用户多次点击启动程序时,生成多个应用实例同时运行,进而引发资源占用过高、功能逻辑冲突(如多个番茄钟同时计时、重复推送通知)等问题。
这一需求的实现过程与此前的踩坑经历形成了鲜明对比:此前依赖 AI 生成的方案屡屡踩坑,而这次我们借助 AI 精准定位到了 Tauri 官方维护的单例插件(tauri-plugin-single-instance),结合插件文档快速完成了集成,一次到位,代码参见上一小节。
消息通知
前文提到双端环境判断的核心目标之一,就是为番茄钟计时结束的消息提醒做差异化实现 ------Web 环境下直接依托 HTML5 标准的 Notification API 完成浏览器通知推送,而客户端环境则需要通过 Tauri 调用 Windows 系统原生通知接口,这一功能的实现核心是集成 Tauri 官方的 tauri-plugin-notification 插件。
该插件的使用逻辑高度清晰,核心围绕 3 个关键 API 展开,也是客户端实现系统通知的必备步骤:
- isPermissionGranted():检测系统是否已授予应用通知权限;
- requestPermission():向操作系统申请通知权限(首次使用时触发);
- sendNotification():发送包含标题、内容的系统原生通知。
官方示例如下:
powershell
import {
isPermissionGranted,
requestPermission,
sendNotification,
} from '@tauri-apps/plugin-notification';
// 你有发送通知的权限吗?
let permissionGranted = await isPermissionGranted();
// 如果没有,我们需要请求它
if (!permissionGranted) {
const permission = await requestPermission();
permissionGranted = permission === 'granted';
}
// 一旦获得许可,我们就可以发送通知
if (permissionGranted) {
sendNotification({ title: 'Tauri', body: 'Tauri is awesome!' });
}
在完成双端环境判断和单一实例控制后,我们着手将 tauri-plugin-notification 插件整合到 Vue 前端代码中,期望实现客户端的系统原生通知。但经过 AI 辅助调试 + 人工反复测试,插件始终无法正常触发通知 ------ 就在排查陷入僵局时,我们意外发现了一个 "非常规现象":原本为 Web 环境设计的 HTML5 Notification API,居然能在 Tauri 客户端中正常运行!
这一发现让我们果断放弃了繁琐的插件集成方案,直接沿用 Vue 端已实现的 HTML5 Notification 逻辑,大幅简化了双端通知的适配成本。但新的问题也随之而来:
1. 通知授权的 "异常" 与体验优化
在客户端环境点击「请求通知授权」按钮时,既没有像浏览器那样弹出系统级的权限确认框,也没有任何视觉反馈,直接提示 "权限已申请";致命的是,每次重启客户端后,授权状态都会丢失,用户必须重新点击授权按钮才能接收通知,体验极差。
针对这一问题,我们没有纠结 "授权状态为何无法持久化" 的底层原因,而是换了个更简单的思路:在番茄钟功能页面初始化(onMounted 生命周期)时,自动执行通知授权检测与申请逻辑。这样一来,用户无需手动点击授权按钮,每次打开客户端都会自动完成授权流程,彻底规避了 "重复授权" 的体验问题。
2. 通知来源显示异常:PowerShell 而非应用名
解决授权问题后,通知虽能在 Windows 右下角正常弹出,但通知的 "来源" 显示为「PowerShell」,而非我们的应用名称「时光助手」------ 这与预期的展示效果相差甚远。
我们再次通过 AI 检索 + 全网搜索排查原因,经过多次无效尝试后,终于得到了确切结论:Tauri 编译的 exe 以 "绿色版" 运行时,Windows 系统无法识别其唯一应用标识;只有将程序制作成安装包并完成安装,Windows 才会将应用的唯一 ID 写入注册表,此时系统通知才能正确识别并显示应用名称,而非默认的 PowerShell。
3. 编译产物移植性问题:缺失 tauri_ui.dll
另一个关键问题出现在程序分发环节:本地编译生成的 exe 文件在开发机上运行正常(因预装了各类依赖组件),但将其直接拷贝到其他电脑运行时,会立即弹出「找不到 tauri_ui.dll」的报错,程序无法启动。这也印证了 "仅编译 exe 不足以满足分发需求"------ 必须制作完整的安装包,将依赖的动态链接库(DLL)、资源文件等一并打包,才能保证程序在纯净环境中正常运行。
构建安装包
这是耗时最长,最困难的一个环节。
执行构建命令pnpm tauri build,过程中会下载 github 的一个用于制作安装程序 wix 包,提示目标计算机积极拒绝,无法连接 (os error 10061),如下:
PS E:\dev\meet\platform-web> pnpm tauri build
Finished `release` profile [optimized] target(s) in 0.75s Built application at: E:\dev\meet\platform-web\src-tauri\target\release\时光助手.exe Info Verifying wix packagefailed to bundle project: `https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip: Connection
Failed: Connect error: 由于目标计算机积极拒绝,无法连接。 (os error 10061)`
Error failed to bundle project: `[https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip:](https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip:) Connection Failed: Connect error: 由于目标计算机积极拒绝,无法连接。 (os error 10061)`
即便开了科学上网,也没有用,于是问 AI,AI 给出了多种方案,如下:
方案 1:直接构建「免安装文件」(最适合你的需求)
你需要的是免安装压缩包,而 Wix 是用来生成 MSI 安装包的工具 ------ 所以可以直接跳过安装包打包步骤,只编译程序本身:
- 打开终端,进入src-tauri目录;
- 执行构建命令(仅编译程序,不生成安装包):bash运行
cargo tauri build --no-bundle - 构建完成后,去路径 E:\dev\meet\platform-web\src-tauri\target\release\ 下,找到这些文件(就是你需要的免安装文件):
○ 时光助手.exe(主程序)
○ tauri.dll(Tauri 核心依赖)
○ resources/ 文件夹(前端资源)
○ vcruntime140.dll 等 VC++ 运行时(如果有的话)
按照方案操作,提示命令不存在,如下图:

方案 2 ,手工下载 Wix 包合配置,如下
如果后续需要生成安装包,可手动下载 Wix 避免网络问题:
- 手动下载 Wix314 二进制包:地址:https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip(若打不开,可通过代理或国内镜像下载)
- 解压到任意目录(比如 C:\wix314);
- 配置系统环境变量:添加 WIX 变量,值为解压目录(比如 C:\wix314);
- 重启终端,重新执行 cargo tauri build 即可。
按照上述方案,依旧不可行,cargo 根本就没有 tauri 的命令参数。
从现象推测,AI 不清楚当前的构建环境,因此从豆包换到了 KIMI,给出了新的解决方案。
方案 1 如下:
- 最简绕过:先不要
.msi,只出.exe便携包pnpm tauri build --bundles exe
验证结果是,exe 参数都不合法,可选的参数只有三个 msi、nsis 和 updater

方案 2 如下:

按要求操作 ,两种方式均无效,还是报同样的错误,第一种方式 tauri 无视,第二种方式直接访问ttps://npm.taobao.org/mirrors/wix314/wix314-binaries.zip,提示 404。
尝试寻找显式关闭自动下载的功能,给的以下配置:

在 IDE 中直接显示 wix 节点下就没有 enabled 和 installUrl 这两个属性,验证直接不通过。
又尝试了多个 AI和给出的五花八门的解决方案,比如解压,放到特定路径,配置环境变量,tauri 打包程序均不认,执意去 github 上下载包,报 10061 错误。
这种疑难杂症,指望 AI 给出解决方案明显不可行了,于是又回到传统模式,去 csdn 根据报错信息去搜索,去除了部分 AI 生成的电子垃圾,以及验证无效的解决方案后,终于找到了一篇可行的博客,参照该博客,操作如下:
通过科学上网,先下载到wix314-binaries.zip这个包,然后解压到 C:\Users${User}\AppData\Local\tarui\WixTools314 目录下,我查看这个目录不存在,需要手工创建。
然后执行打包命令,虽然依然报错,但报错信息已经发生了变化,如下:
PS E:\dev\meet\platform-web> pnpm tauri build
Compiling 时光助手 v3.4.0 (E:\dev\meet\platform-web\src-tauri)
Finished
releaseprofile [optimized] target(s) in 51.23sBuilt application at: E:\dev\meet\platform-web\src-tauri\target\release\时光助手.exe
Info Target: x64
Running candle for "main.wxs"
Running light to produce E:\dev\meet\platform-web\src-tauri\target\release\bundle\msi\time-helperV3.4_3.4.0_x64_en-US.msi
Error failed to bundle project: error running light.exe: `failed to run
提示 light.exe 失败,继续搜索,有人说是对中文支持不好,需要路径无空格,避免使用非ASCII 字符,只能使用英文和数字的组合形式,于是将下面的 title 改成了 TimeHelper,如下图:

再次打包,light.exe 不报错了,提示了新的错误如下:
PS E:\dev\meet\platform-web> pnpm tauri build
Compiling TimeHelper v3.4.0 (E:\dev\meet\platform-web\src-tauri)
Finished `release` profile [optimized] target(s) in 59.79s Built application at: E:\dev\meet\platform-web\src-tauri\target\release\TimeHelper.exe Info Target: x64 Running candle for "main.wxs" Running light to produce E:\dev\meet\platform-web\src-tauri\target\release\bundle\msi\TimeHelperV3.4_3.4.0_x64_en-US.msi Info Verifying NSIS package Downloading [https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip](https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip)failed to bundle project: `https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip: Connection Failed: Connect error:
Error failed to bundle project: `[https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip:](https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip:) Connection Failed: Connect error: 由于目标计算机积极拒绝,无法连接。 (os error 10061)`
手工下包 https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip,然后解压到C:\Users${User}\AppData\Local\tarui\NSIS这个目录下。
这还不够,需要下载https://github.com/tauri-apps/binary-releases/releases/download/nsis-plugins-v0/NSIS-ApplicationID.zip解压到NSIS/Plugins目录下,将NSIS-ApplicationID\ReleaseUnicode\ApplicationID.dll复制到NSIS/Plugins/x86-unicode下。
错误提示变成了下面这样:
Warn NSIS directory contains mis-hashed files. Redownloading them.
failed to bundle project: https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.4.1/nsis_tauri_utils.dll: Connection Failed: Connect error: 由于目标计算机积极拒绝,无法连接。 (os error 10061)
继续手工下载 nsis_tauri_utils.dll复制到NSIS/Plugins/x86-unicode下。
最后构建,终于打包成功,没再有报错了:
PS E:\dev\meet\platform-web> pnpm tauri build
Finished
releaseprofile [optimized] target(s) in 1.24sInfo Target: x64
Running candle for "main.wxs"
Info Target: x64
Running makensis.exe to produce E:\dev\meet\platform-web\src-tauri\target\release\bundle\nsis\TimeHelperV3.4_3.4.0_x64-setup.exe
E:\dev\meet\platform-web\src-tauri\target\release\bundle\msi\TimeHelperV3.4_3.4.0_x64_en-US.msi
E:\dev\meet\platform-web\src-tauri\target\release\bundle\nsis\TimeHelperV3.4_3.4.0_x64-setup.exe
构建安装包这一步,折腾了差不多 1 天时间。最终打出来的安装包确实很小,只有 5M 多一点,很精巧。
如何打中文安装包
默认打包出来的安装程序是英文的,安装过程全部是英文,用户体验不太好,如想打中文语言包,需修改下配置文件:

注意这里的配置只对 msi 有效,至于另外一种工具 nsis,我并不需要,直接就弃了,将 targets 也改成了 msi。
还有一个问题在于,前面验证 light.exe 报错,当时以为是中文问题,但是这个属性配置成英文,实际影响的是桌面应用的标题栏,用户体验也不好,如下图:

在反复打包的尝试中,发现 lights.exe 报错,跟这里是不是中文根本没关系,放英文也有可能失败,放中文也有可能成功,很像是自身不稳定导致的打包失败,多试几次就好了。
疑问点
基于 Tauri 构建的客户端程序,观察其内存占用情况,会发现两种形态,如下图:
一种是应用自身占用内存很低,只有 1 个进程 30M 左右,但是在外部游离着几个 Miscrosoft Edge WebView2 的进程,占用内存 50~100M 不等。

另外一种形态是应用显示多个子进程,子进程中显示 Miscrosoft Edge WebView2,合计起来占内存也得 200M~300M 的样子,如下图:

AI 给的答案如下:
图里描述的两种"形态"都是 Chromium 多进程架构的正常表现,不是内存泄漏,也不是 Tauri 专属。
核心原因:WebView2(= Chromium)为了稳定性 + 安全沙箱,会把工作拆到不同进程,数量由页面复杂度、GPU、网络、存储等模块决定,Tauri 控制不了。
- 为什么有"游离"WebView2 进程(30 MB vs 50-100 MB)
- 你的 主进程(TimeHelper.exe ≈ 30 MB)只是 Rust 代码 + 窗口管理;
- 首次创建 WebView 时,系统会拉起 WebView2 浏览器内核(msedgewebview2.exe),它再按需孵化:
- Browser 进程(主控,50-70 MB)
- GPU 进程(硬件加速,30-60 MB)
- Network/Storage/Utility(各 5-15 MB)
这些进程挂在"WebView2 Runtime"名下,任务管理器把它们跟你的 exe 分开显示 → 看上去像"外部游离",其实隶属同一应用。
- 为什么会有"子进程"形态(200-300 MB)
任务管理器 → "进程"标签页 按 Pid 树 展开时,会把 WebView2 各子进程挂到你的 exe 下(见下图"SWebView2: 时光助手"),于是出现:
plain
时光助手 (主 30 MB)
├─ WebView2 GPU 进程 104 MB
├─ WebView2 管理器 50 MB
├─ WebView2 NetworkService 6 MB
└─ WebView2 StorageService 3 MB
合计 ≈ 200 MB,只是展示方式不同,内存总量跟"游离"时几乎一样。
- 进程数量由什么决定
| 进程角色 | 触发条件 | 大致内存 |
|---|---|---|
| Browser | 只要用了 WebView | 50-70 MB |
| GPU | 硬件加速开启(默认) | 30-60 MB |
| Renderer | 每打开一个 <iframe> /新窗口 |
20-40 MB × N |
| Network | 首次网络请求 | 5-10 MB |
| Storage | 首次 localStorage/IndexedDB | 3-6 MB |
| Utility | 音视频、解码、打印 | 5-10 MB |
因此:
- 空页面 → 3-4 进程,总 120 MB 左右
- 多 iframe、大 Canvas、视频 → 6-8 进程,总 200-300 MB
都是 Chromium 正常调度。
TRAE 彻底崩了
最后再提一点,TRAE 满负荷运转了 3 天,多次把上下文 178K 消耗到 60%左右的时候,就"罢工"了,一方面跟你说它在工作,另一方面实际没有任何运转(无思考过程无日志变化,显示任务已完成),如下图:


在初始化构建环节居功至伟,在后期运行任务的时候突然崩溃了,一打开就提示如下图:

进行了卸载,手工删除工作区域所有文件(C:\Users\wqliu\AppData\Roaming\Trae CN),重装,更换安装目录,重新执行初始化向导,更换其他项目,尝试了 5 次以上,均无法恢复正常,经常报错是crashed,错误码还每次不一样,然后官网上也没找到对应的错误码自查页面。
只能搁置一段时间了,也许下个版本才能恢复正常。
反思与总结
AI的底层生成机制,决定了"幻觉"问题的不可避免性------但程序开发是极度严谨的工作,哪怕是参数名写错、API调用方式偏差这类"丁点错误",都会直接导致功能完全不可用。这种矛盾在对接多版本第三方框架/组件时,体现得尤为突出。
第三方框架(如Tauri)往往存在多个大版本(1.x/2.x)及数十个小版本,不同版本的配置结构、API方法、参数格式差异显著,且官方文档常存在描述简略、逻辑含糊的问题;在没有AI的时代,开发者也只能对着文档逐行摸索、反复验证测试、逐一排查问题,这个过程虽耗时,但至少是"基于官方基准的试错"。
而AI的核心问题在于:它输出的是"最大概率的答案",而非"精准匹配版本的正确答案",这就极易产生"张冠李戴"的情况。以Tauri框架为例,当询问某个功能的实现方案时,AI给出的结果往往是"混合了1.x和2.x版本特性的虚构信息"------比如把1.x的全局变量(window.__TAURI__)和2.x的插件调用逻辑拼接在一起,表面上逻辑通顺、代码完整,误导性极强;但实际验证时,要么直接报错,要么功能完全不符合预期。
更让人无奈的是,当人工验证后反馈"方案不可用",AI虽会立刻承认"误用了1.x版本配置,应参考2.x文档",但再次输出的方案,依然大概率是"1.x/2.x混杂的错误版本",本质上并未解决"版本精准匹配"的核心问题。
此外,用AI排查"多问题交织"的场景时,还会陷入"按起葫芦浮起瓢"的死循环:比如同时修复"托盘最小化"和"消息通知"两个问题,AI给出的方案可能解决了A问题,却触发了B问题;修复B问题后,A问题又恢复原状。即便明确告知AI"需兼顾两个问题同时解决",反复迭代几轮后,依然无法跳出这个循环------这种需要全局逻辑分析、多场景权衡的问题,AI根本无法处理,最终必须依赖人工梳理完整逻辑、逐行校验代码,才能从根源上解决。
这一过程也印证了一个关键认知:AI更适合作为"信息检索的辅助工具"(比如快速定位官方插件、梳理基础逻辑框架),而非"精准解决版本适配、多问题交织的核心工具"。程序开发中,涉及版本匹配、逻辑闭环、多场景兼容的核心问题,最终仍需回归"人工研读文档+逐行验证+全局逻辑分析"的传统方式------AI可以节省"信息搜集"的时间,但无法替代"精准验证"和"逻辑闭环"的核心工作。