桌面端选型是个吵了十年的话题。前几天我把自己一个 A 股盯盘工具从「Electron 那一套」换成了 Rust + Vue(Tauri 2) ,顺手把市面上主流的 6 种跨平台桌面方案横向比了一遍------不比口号,只比能测出来的东西:安装包多大、靠什么渲染、前端代码能不能直接搬、分发和签名要折腾多少、以后要不要重写。
结论先放这儿:Windows x64 安装包,Electron 系做到了 224 MB 和 104 MB,我这套做到了 4.7 MB。差距不是"优化出来的",是架构决定的。但 Tauri 也不是没有代价,第五节的劝退条款和第七节的踩坑清单,建议你比结论看得更仔细。
一、先把"桌面端开发"拆成三条路线
大多数人争论时把不同物种放在一起比,所以永远吵不出结果。桌面端方案按渲染层怎么来的,其实只有三条路线:
scss
① 自带渲染引擎(把浏览器打包进安装包)
Electron / CEF / NW.js ------ 你发的是"一个私有的 Chromium"
② 用系统 WebView(前端代码 + 宿主语言的本地壳)
Tauri(Rust) / Wails(Go) / .NET MAUI-WebView ------ 你发的是"一个壳 + 前端产物"
③ 自己画像素 / 用原生控件(不经过浏览器)
Flutter Desktop(自绘) / Qt(自绘+原生控件) / Avalonia(自绘) / MAUI(原生控件) / 纯原生
三条路线的成本结构完全不同:
- 路线 ① 的成本在分发:每个应用都背一份 Chromium,安装包上百 MB、内存基础开销几百 MB,但换来了"一套代码、全平台渲染完全一致";
- 路线 ② 的成本在兼容性验证:安装包只有几 MB,但 Windows 用 WebView2(Chromium)、macOS 用 WKWebView(跟系统 Safari 绑定)、Linux 用 WebKitGTK(版本参差),一个 UI 要在三种引擎上验;
- 路线 ③ 的成本在人力:UI 要重写,前端资产基本归零,但能拿到最一致的绘制结果和最好的性能上限。
选型问题本质上是:你把成本放在分发、验证,还是人力上。
二、6 种主流方案横评(带实测数据)
先上表。数据口径我在第三节说明,避免"某博客说"式引用。
| 方案 | 运行时/渲染 | 开发语言 | Windows 安装包量级 | 前端资产复用 | 移动端延伸 | 许可与商业化 |
|---|---|---|---|---|---|---|
| Electron | 打包 Chromium + Node | JS/TS | 100--230 MB(实测 VS Code 224 MB、Notion 104 MB) | ★★★★★ 完全复用 | 无(各自另做) | MIT,无附加条件 |
| Tauri 2 | 系统 WebView + Rust 宿主 | Rust + 任意前端 | 4--15 MB(实测 4.7 MB) | ★★★★★ 完全复用 | ✅ iOS/Android 同一套前端 | MIT/Apache-2.0 |
| Wails | 系统 WebView + Go 宿主 | Go + 任意前端 | 与 Tauri 同量级(几 MB~十几 MB) | ★★★★★ 完全复用 | v3 才开始支持 | MIT |
| Flutter Desktop | 自绘(Skia/Impeller),不自带浏览器 | Dart | 20--60 MB 量级 | ✗ 要用 Dart 重写 UI | ✅ 一套代码五端 | BSD-3 |
| .NET MAUI | 原生控件抽象层 | C#/XAML | 视运行时裁剪方式,几十 MB 起 | ✗ | ✅ | MIT(.NET 开源) |
| Avalonia | 自绘,不依赖系统 UI 框架 | C#/XAML | 30--70 MB 量级(取决于是否 self-contained) | ✗ | 桌面为主,移动在推 | MIT |
| Qt 6 | 自绘 + 原生控件 | C++/QML(或 PySide) | 视部署方式,30--80 MB | ✗ | ✅ | 开源 LGPLv3 / 商用授权 |
各版本当前状态(我逐个查了官方源,日期 2026-09-14):
| 项目 | 最新稳定版 | 来源 |
|---|---|---|
| Tauri(crate) | 2.11.5(2.0 稳定版发布于 2024-10-02) | crates.io / 官方博客 |
| Electron | v44.3.0(2026-09-08) | GitHub Releases API |
| Wails | 稳定线 v2.14.0;v3 仍在 beta(v3.0.0-beta.20) | GitHub Releases API |
| Flutter | 3.47.4 stable(Dart 3.13.3,2026-09-11) | Flutter 官方 release JSON |
| Avalonia | 12.1.2 | NuGet |
| .NET | 10.0.12(LTS);11 在 RC | Microsoft release metadata |
| Qt | 6.10.3 / 6.11 系列 | 官方发布页 |
热度参考(GitHub Star,同日抓取):Electron 123,034 、Tauri 111,042 、Wails 36,230。纯看数字,Tauri 已经追到 Electron 同一个量级------这在两年前不可想象。
逐个说人话
Electron:成熟度没有对手。VS Code、Notion、Slack、Discord 都在用,遇到问题一搜就有答案,主进程/渲染进程模型清晰,Node 全能力在手(串口、打印、注册表、系统 API 都有现成轮子)。代价就是那 100--230 MB:**每个应用背一份 Chromium。**如果你的用户在国内用移动网络下载,224 MB 的安装包和 4.7 MB 的安装包,是完全不同的两个产品体验。
Tauri 2 :Rust 做宿主,前端产物由系统 WebView 渲染。2024 年 10 月 2.0 转正,同时带来 IOC(多平台)支持------同一套 Vue/React 前端可以编到 iOS/Android。它的取舍是明确的:省下的是运行时体积,付出的是多引擎兼容验证。
Wails :Go 团队的 Tauri。架构思路一致(系统 WebView + Go 宿主),v2 稳定、生态齐;v3 至今仍是 beta(beta.20),引入了更现代的多窗口/服务化设计,但我不建议把生产项目压在 beta 上。
Flutter Desktop :唯一"一套代码覆盖桌面+移动+Web 且渲染完全自研"的选项,UI 一致性最好,动画性能高。但它是另一套 UI 生态:你现有的 Vue/React 组件、CSS、图表库全部归零,要用 Dart 重写。桌面端插件生态相比移动端仍然薄。
MAUI / Avalonia:.NET 阵营的两条路。MAUI 抽象原生控件,走的是一致性稍弱但"原生感"更强的路线(Windows/macOS 支持成熟,Linux 不在官方名单);Avalonia 自绘、跨平台最完整,社区活跃,12.x 已经相当稳。选它俩的前提是团队本来就是 C#。
Qt 6 :工业、医疗、嵌入式、需要 10 年长期维护的场景,Qt 依然是第一选择,商业授权能买到确定性。但 LGPLv3 的动态链接对闭源商业应用的合规要求需要法务确认,且 C++ 开发效率摆在那里------前端团队用 Qt,等于放弃已有的一切积累。
三、数据口径与证据强度(重要)
技术文章最怕数字来源不明。我把上面每个数字的来路讲清楚,你自己判断信不信:
| 数字 | 怎么来的 | 证据强度 |
|---|---|---|
| VS Code 安装包 224 MB | curl -IL 官方更新端点,拿到 Content-Length: 235072944(VSCodeUserSetup-x64-1.137.0.exe) |
实测,可复现 |
| Notion 安装包 104 MB | 同上,跳转链最终 Content-Length: 108831832(Notion Setup 7.33.0) |
实测,可复现 |
| Tauri 侧 4.7 MB / 6.5 MB / 13.1 MB | 我自己的项目 Release 资产大小,GitHub API 直读字节数 | 实测,可复现 |
| 各大框架最新版本号 | crates.io / GitHub Releases / NuGet / 官方 release JSON | 一手来源 |
| Electron 系"100--230 MB"区间 | 上表两个实测点 + Electron 应用普遍分布 | 中等(不同应用裁剪差异大) |
| Flutter / MAUI / Avalonia / Qt 体积区间 | 社区共识区间,未逐项实测 | 弱(量级参考,别当精确值) |
| "Tauri 内存是 Electron 的几分之一" | 机制上成立(不捆 Chromium),但具体倍数强依赖应用形态 | 弱(我在下文只讲机制,不给倍数) |
一句话规矩:装到用户机器上的安装包字节数,我只信 Content-Length 和自己的 Release 资产;倍数关系只讲机制,不讲玄学。
四、为什么我最后选了 Rust + Vue
不是因为它新,而是因为这 5 条对我这套场景是"硬收益"。
1. 分发成本直接降一个数量级
Downloading 224 MB 和 4.7 MB,是两个不同的用户决策。差的不只是带宽,还有:
- 安装包的更新换代成本(用户每次升级都要重下这么大一坨);
- 只装在 C 盘不够的机器上的空间焦虑;
- 企业内网、离线分发、U 盘携带的场景(我做了一份 6.4 MB 的绿色版 zip,解压即用)。
我把一整套跨平台产物实测列出来(v1.4.6,GitHub Release 资产字节数):
| 平台/产物 | 大小 | 说明 |
|---|---|---|
Windows NSIS .exe |
4.68 MB | 主力分发格式 |
Windows .msi |
6.51 MB | 企业域分发用得着 |
Windows 绿色版 .zip |
6.44 MB | 解压即用,数据在程序目录 |
macOS 通用 .dmg |
13.14 MB | Intel + Apple Silicon 合一 |
Linux .deb / .rpm |
8.05 MB | 依赖系统 webkit2gtk |
Linux .AppImage |
79.3 MB | 见第七节第 4 条,这个数字很真实 |
顺手打个假:网上说"Tauri 应用都是几 MB",那只对 Windows/macOS 的安装包成立。AppImage 会把依赖链一起打进去,实测 79.3 MB------所以别拿"Tauri 只有 4 MB"去承诺 Linux 用户。
2. 前端资产零迁移,开发体验还是 Vite
这点被严重低估。Tauri 的前端就是一个普通 Web 项目:
ts
// package.json ------ 没有任何 Tauri 特有依赖侵入前端
"dependencies": {
"@tauri-apps/api": "^2",
"klinecharts": "^10.0.2",
"naive-ui": "^2.44.1",
"pinia": "^3.0.4",
"vue": "^3.5.13"
}
Vite HMR 照常,Vue DevTools 照常,Pinia / Naive UI / KLineChart 全部直接搬。**我在 Web 端攒的组件、样式变量、主题切换方案,一行没重写。**这是 Electron 之外所有框架(Flutter/Qt/MAUI/Avalonia)都给不了的------它们都要求你把 UI 用另一套语言重画一遍。
3. 重活下沉到 Rust,前端只管渲染
这是 Tauri 相比"前端调系统 API"式方案最大的不同:你可以自己决定哪些逻辑放在 Rust 侧。我这套工具里前端只有约 5,200 行(含 Vue/TS/CSS),Rust 侧约 4,300 行,各司其职:
| 下沉到 Rust 的能力 | 解决什么问题 |
|---|---|
reqwest 共享连接池 + 统一超时 |
前端不做 HTTP,没有 CORS、没有跨域凭据问题 |
GBK → UTF-8 解码(encoding_rs) |
行情接口返回 GBK,浏览器 fetch 处理起来很难受 |
rusqlite(bundled SQLite) |
离线缓存行情,重启即有数据,不依赖 Node 原生模块编译 |
tokio 后台轮询调度器 |
定时任务不占用 WebView 主线程,窗口卡不掉 |
| 多数据源适配与回退 | 腾讯源挂了自动切新浪源,对前端完全透明 |
举个真实片段------数据源抽象 + 共享连接池,这是我看重的"工程感":
rust
#[async_trait]
pub trait DataSource: Send + Sync {
fn name(&self) -> &str;
async fn fetch_quotes(&self, codes: &[String]) -> Result<Vec<Quote>, AppError>;
async fn fetch_depth(&self, code: &str, market: &str) -> Result<Depth, AppError>;
async fn fetch_minute_data(&self, code: &str, market: &str) -> Result<Vec<MinuteData>, AppError>;
// ...
}
// Client::clone() 是浅拷贝:连接池、TLS 配置、超时全部共享
static SHARED_CLIENT: OnceLock<Client> = OnceLock::new();
pub fn shared_client() -> &'static Client {
SHARED_CLIENT.get_or_init(|| {
Client::builder()
.timeout(Duration::from_secs(10))
.pool_max_idle_per_host(10)
.build()
.expect("Failed to build shared reqwest Client")
})
}
而"主源拿不到数据时静默回退"这种逻辑,写在 Rust 侧只有二十行,且前端完全无感:
rust
#[tauri::command]
pub async fn get_intraday(
code: String, market: String,
manager: State<'_, Arc<DataSourceManager>>,
) -> Result<Vec<MinuteData>, String> {
// 优先用活跃源;返回空时回退到备用源(如主源对北交所代码无分时数据)
let active_name = manager.active_name();
if let Some(source) = manager.get_source(&active_name) {
if let Ok(data) = source.fetch_minute_data(&code, &market).await {
if !data.is_empty() { return Ok(data); }
}
}
for (name, source) in manager.all_sources() {
if name == active_name { continue; }
match source.fetch_minute_data(&code, &market).await {
Ok(data) if !data.is_empty() => return Ok(data),
Ok(_) => {}
Err(e) => log::warn!("分时回退数据源 {} 失败: {}", name, e),
}
}
Ok(vec![])
}
4. 进程模型干净,安全模型是"白名单式"的
Electron 里渲染进程和 Node 同源,安全全靠你自觉配 contextIsolation / preload;Tauri 里前端根本碰不到 Node 和系统,只有你显式注册的命令能被调用:
rust
#[tauri::command]
pub fn get_quotes(cache: State<'_, Arc<QuoteCache>>) -> Vec<Quote> {
cache.get_all_quotes()
}
配合 tauri.conf.json 里的 CSP,前端连外链脚本都加载不了:
json
"security": {
"csp": "default-src 'self'; img-src 'self' asset: https://raw.githubusercontent.com; \
style-src 'self' 'unsafe-inline'; script-src 'self'"
}
对一个要处理用户自选股、本地数据库、还要联网的桌面应用来说,"默认没有权限、能力靠显式声明" 比"默认全有权限、靠开发者记得关"要安全得多。
5. 一套前端,将来能编到移动端
Tauri 2 的 IOC 支持意味着这套 Vue 前端理论上可以直接编到 iOS/Android(WebView 换成系统 WebView,Rust 复用)。我个人暂时不做移动端,但**"以后要做时不用重写"这件事,本身就是选型价值**------Flutter 之外,只有 Tauri 给了这条退路。
五、诚实劝退:Rust + Vue 的 5 个代价
写到这里必须泼冷水。如果你只看到上面那些,上线后会很难受。
1. WebView 碎片化是真问题,不是"注意一下"就能过。 Windows 是 WebView2(Chromium,能自更新),macOS 是 WKWebView(跟系统 Safari 版本绑定,官方文档明确说:不再维护的 macOS 版本收不到 WebKit 更新),Linux 是 WebKitGTK(各发行版版本参差,官方参考表里从 2.20 到 2.36 都有)。**你的 CSS/JS 要在 Chromium 和 WebKit 两套引擎上都验,只测 Windows 等于没测。**我用 Playwright 跑测试时也踩过这个坑------Chrome 内核全绿,真机 macOS 上布局就是不一样。
2. 首次运行有 WebView2 依赖。 官方文档的说法是:WebView2 支持 Windows 7 及以上,Windows 11 已预装 ;比 Windows 11 老的系统,Tauri 生成的安装器会负责确保 WebView2 被安装。也就是说:联网环境基本无感,纯离线/内网分发的场景要额外准备一份 WebView2 运行时,别等到客户现场才想起来。
3. Rust 的学习曲线和编译时间要有人买单。 首次全量编译十几分钟起步。团队里必须有人能看懂 Rust 的 async/Send/生命周期错误------报错信息虽然友好,但对没写过 Rust 的同学依然是道墙。如果你的团队全是前端且不打算学 Rust,Tauri 的优势会打折(能用到的大概只有"体积小"这一条)。
4. 生态密度不如 Electron。 Electron 十年的 Stack Overflow 沉淀,Tauri 没有。Tauri 的问题更多靠官方文档 + Discord + GitHub Issue 解决,插件质量也确实参差(官方插件最稳,社区插件要自己读源码确认)。遇到冷门需求时,你花在解决问题上的时间会更多。
5. Linux 分发仍然是脏活。 上面那个 79.3 MB 的 AppImage 就是证据。此外各发行版的 webkit2gtk 版本、Wayland 下的窗口行为、托盘图标实现,都是要单独测的。如果你的用户里 Linux 占比很高,请把这一项工时单独估进去。
六、落地架构:三层切分 + 事件驱动的桥
选型定了,真正的工程问题是前后端边界画在哪。我这套是三层:
arduino
┌─────────────────────────────────────────────┐
│ Vue 3 表现层(Pinia + Naive UI + KLineChart)│ ← 只做渲染 + 交互
├─────────────────────────────────────────────┤
│ Tauri IPC 桥(命令 invoke ↑ / 事件 listen ↓)│ ← 22 个命令,职责单一
├─────────────────────────────────────────────┤
│ Rust 数据层(多源适配 / 缓存 / 调度 / SQLite)│ ← 网络、解析、持久化、定时
└─────────────────────────────────────────────┘
6.1 关键设计:后端主动推,而不是前端轮询
新手最容易犯的错是"前端定时 invoke 拉数据"。我这边反过来:Rust 侧调度器按自适应频率抓数据 → 更新缓存 → 向前端发事件,前端只订阅:
ts
// stores/quote.ts ------ 事件驱动,前端一次 invoke 都不发(除了启动补快照)
unlistenQuotes = await listen<Quote[]>('quotes-updated', (event) => {
const map = new Map<string, Quote>()
for (const q of event.payload) map.set(`${q.market}:${q.code}`, q)
quotes.value = map
lastUpdate.value = Date.now()
})
好处很直接:推送频率由后端统一决定(交易时段 2s、午休 10s、休市 30s),前端不需要知道什么时候该快、什么时候该慢;而且整批数据一次到位,不会有 N 个组件各拉各的。
6.2 一个必踩的竞态:事件比监听器先到
后端调度器在窗口还没渲染完时就可能推了第一批数据,前端 listener 是后注册的------首屏空白就是这么来的 。修复方式很简单:订阅完事件,再 invoke 一次拉当前缓存快照兜底(代码注释我当时写得很清楚):
ts
// Pull initial state from the backend cache to cover the race window
// where the scheduler already emitted data before listeners were ready.
const [cachedQuotes, cachedIndices] = await Promise.all([
invoke<Quote[]>('get_quotes'),
invoke<IndexQuote[]>('get_indices'),
])
6.3 让 CPU 降温:三态自适应轮询
行情工具最怕"死循环定时器"。A 股一天只有 4 小时在交易,节假日更是一动不动------如果每 2 秒抓一次数据、抓 8 小时,你的程序就是个电老虎。我写了个三态状态机(Rust 侧):
rust
enum PollingState {
Probing { remaining: u32 }, // 开盘探测:每 2s 抓,看价格动不动
Normal { unchanged_streak: u32 }, // 正常交易:按会话频率
Idle, // 判定休市(节假日):降到 30s
}
impl PollingState {
fn update(&mut self, prices_changed: bool, session: MarketSession) -> u64 {
match self {
Self::Probing { remaining } => {
if prices_changed {
*self = Self::Normal { unchanged_streak: 0 };
return session.recommended_interval();
}
*remaining -= 1;
if *remaining == 0 { *self = Self::Idle; return IDLE_INTERVAL; }
PROBE_INTERVAL
}
Self::Normal { unchanged_streak } => {
if prices_changed { *unchanged_streak = 0; }
else {
*unchanged_streak += 1;
if *unchanged_streak >= STREAK_THRESHOLD { // 连续 10 次无变化
*self = Self::Idle; return IDLE_INTERVAL;
}
}
session.recommended_interval()
}
Self::Idle => {
if prices_changed { *self = Self::Normal { unchanged_streak: 0 }; }
IDLE_INTERVAL
}
}
}
}
逻辑很土但很有效:开盘先探三次,价格动了 = 真开市;连续 10 次价格没动 = 大概率节假日,降频到 30 秒 。一旦发现价格又动了,立刻回到正常频率。MarketSession 用固定 UTC+8 计算,不依赖用户机器的本地时区------这行代码是给海外出差用户留的。
6.4 多窗口 / 托盘:Tauri 的配置式多窗口
那个"可拖到屏幕任意角落的浮动行情条"就是一个独立窗口 + 独立前端入口:
json
{
"label": "ticker",
"url": "ticker.html",
"width": 230, "height": 38,
"decorations": false,
"alwaysOnTop": true,
"skipTaskbar": true,
"resizable": false,
"focus": false
}
这里有个很深的坑:Tauri 的 skipTaskbar 走的是 COM 的 ITaskbarList::DeleteTab,Windows 资源管理器重启后,窗口会重新出现在任务栏上 。解法是直接给窗口加 WS_EX_TOOLWINDOW 扩展样式(Rust 侧调 Win32 API):
rust
const GWL_EXSTYLE: i32 = -20;
const WS_EX_TOOLWINDOW: isize = 0x80;
pub unsafe fn set_tool_window(hwnd: isize) {
let ex_style = GetWindowLongPtrW(hwnd as HWND, GWL_EXSTYLE);
if ex_style & WS_EX_TOOLWINDOW != 0 { return; } // 幂等
SetWindowLongPtrW(hwnd as HWND, GWL_EXSTYLE, ex_style | WS_EX_TOOLWINDOW);
SetWindowPos(hwnd as HWND, std::ptr::null_mut(), 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
}
这一段在 Electron 里要写原生模块,在 Tauri 里就是一个 #[cfg(target_os = "windows")] 模块 + 几个 extern 函数------宿主是 Rust 的另一个好处。
6.5 发版:一个 tag 出全平台包
打包矩阵、签名、自动更新、CHANGELOG 抽正文、绿色版 zip------这套我在上一篇里写透了,这里只给结果:推一个 tag,Windows/macOS/Linux 三平台产物 + 自动更新元数据全自动产出,0 服务器 0 成本。
七、踩坑清单(收藏这张表)
| 症状 | 真因 | 解法 |
|---|---|---|
| 首屏空白,第二次打开又正常 | 后端事件先于前端 listener 注册 | 订阅后再 invoke 拉一次缓存快照兜底 |
| macOS 上滚动条/圆角/字体和 Windows 不一致 | WebView2(Chromium) vs WKWebView(WebKit) | 双引擎真机验证,别只跑 Chromium 测试 |
| 老系统启动白屏 | WebView2 运行时缺失 | 安装器引导安装;离线场景预置运行时 |
| CPU 一直 10% 以上下不来 | 定时器无脑高频轮询 | 三态自适应轮询(开盘探测/正常/降频) |
| Linux 包比 Windows 大十几倍 | AppImage 把 webkit2gtk 依赖链打进去了 | 接受它,或优先发 .deb/.rpm |
| 资源管理器重启后迷你条跑回任务栏 | skipTaskbar 的 COM 方案不持久 |
加 WS_EX_TOOLWINDOW 扩展样式 |
| 打包后白屏,dev 正常 | CSP / 资源路径 / frontendDist 配错 |
tauri build --debug 打开控制台查 |
| 更新静默失败、日志没报错 | updater 的坑(有三类) | 见我的上一篇:《0 元成本搞定桌面端自动更新》 |
| 安装包还能更小吗 | 默认 Cargo profile 没优化 | 官方文档给了 profile:lto=true、opt-level="s"、panic="abort"、strip=true,另可开 build.removeUnusedCommands 砍掉未授权命令 |
八、这套组合在我项目上的实际结果
上面每一节都不是纸上推演。我把它用在开源项目 QuantDesktop(一个 A 股盯盘工具)上了,数据都是真的:

工程规模 :前端 5,226 行(Vue 3 + TS + CSS,41 个文件)+ Rust 4,314 行(17 个文件),22 个 #[tauri::command] 就是全部的前后端契约。对个人项目来说,这个体量一个月内做到 1.4.6 版本、覆盖三平台,靠的就是"前端资产零迁移 + Rust 干重活"。
几个实现层面的选择:
- 行情能力:多数据源(腾讯/新浪)适配 + 自动回退,GBK 统一解码,量额归一化(手→股、万元→元);
- 调度:三态自适应轮询 + 交易时段判定(固定 UTC+8,节假日靠"价格静止"识别);
- 持久化:SQLite 缓存报价与自选,重启即有数据;
- 窗口:主窗口 + 无边框置顶迷你行情条(双前端入口)+ 系统托盘;
- 分发:NSIS/MSI/dmg/deb/rpm/AppImage + 绿色版 zip,内置静默自动更新(交易时段不弹打扰弹窗)。
项目地址(Windows / macOS / Linux 安装包与绿色版都有): github.com/Leaderxin/q...
前两篇姊妹篇,正好把这条链路的上下游补齐了:
- 选型之后要发布 → 《0 元成本搞定桌面端自动更新:Tauri + GitHub Releases 全流程实录》
- 想看这个项目怎么起步 → 《cc-switch 同款 Tauri + Rust 架构,我做了个免费 A 股盯盘神器》
九、一句话选型(抄走就能用)
bash
你的团队是「前端 + 愿意碰 Rust」?
├─ 是 → 体积/内存是卖点(下载站分发、内网、绿色版)?
│ ├─ 是 → Tauri 2 + Rust + Vue/React ✅(本文这套)
│ └─ 否 → 需要 Node 全生态/复杂系统集成?
│ ├─ 是 → Electron(成熟压倒一切)
│ └─ 否 → Tauri 2(省下的体积迟早有人感谢你)
└─ 否 → 主力语言是?
├─ Go → Wails(等 v3 转正,或先用 v2)
├─ C# → Avalonia 12(跨平台最全)/ MAUI(要原生控件观感)
├─ Dart/移动端一起做 → Flutter Desktop
└─ C++/工业长期维护 → Qt 6(提前理清 LGPL 合规)
再补三句经验:
- 能用 Web 技术就别重画 UI------除非你的产品卖点就是原生观感或绘制性能;
- 安装包体积是产品指标,不是技术洁癖------4.7 MB 和 224 MB 的转化率差异,做过分发的人都懂;
- 选框架时把"验证成本"算进工时:系统 WebView 方案省的是分发,花的是多引擎测试;打包 Chromium 方案省的是测试,花的是分发。
写在最后
桌面端框架之争,最后往往不是技术之争,而是你愿意把成本放在哪的选择:放在用户的硬盘和带宽上(Electron),放在自己的兼容性验证上(Tauri/Wails),还是放在重写 UI 的人力上(Flutter/Qt/MAUI/Avalonia)。
我这套选择的理由很简单:我的用户在国内、用普通家宽下载、很多人只想「下载下来就能用」,那我就必须把体积和启动体验做到极致------剩下的验证成本,我自己扛。
如果你也在纠结桌面端选型,欢迎在评论区告诉我你的场景(团队语言、用户地域、要不要移动端),我可以帮你把这张账算得更细。代码和安装包都在 GitHub 上,装了觉得有用的话,给个 Star 就是最大的支持。
本文所有体积数据均为 2026-09-14 实测:Electron 系安装包取自官方更新端点返回的
Content-Length,Tauri 侧取自项目 GitHub Release 资产字节数;框架版本号取自 crates.io / GitHub Releases / NuGet / 官方 release metadata。区间值为社区共识,已在第三节标注证据强度。