用Tauri 2.0构建跨平台桌面应用:比Electron小100倍的真正轻量级方案

发布时间:2026/7/25 8:58:23
用Tauri 2.0构建跨平台桌面应用:比Electron小100倍的真正轻量级方案 用Tauri 2.0构建跨平台桌面应用比Electron小100倍的真正轻量级方案Electron的致命缺陷越大越慢Electron是用Web技术构建桌面应用的最流行方案VS Code、Slack、Discord都用它。但它有个致命缺陷体积大、内存占用高。一个Hello World的Electron应用打包后约120MB-150MB。原因是Electron把整个Chromium浏览器 Node.js运行时都打包进去了。对于独立开发者的小工具如Markdown编辑器、API测试工具这太重了。Tauri的解决方案用系统自带的WebViewTauri不用Chromium而是用操作系统自带的WebViewWindowsWebView2基于Edge/ChromiummacOSWKWebView基于Safari/WebKitLinuxWebKitGTK结果同样的Hello WorldTauri打包后约3MB-5MB——比Electron小30-50倍。Tauri 2.0核心架构前端 Rust后端Tauri 2.02024年发布用前端React/Vue/Svelte Rust后端的架构。为什么用Rust做后端安全性Rust的内存安全保证避免了很多Electron常见的远程代码执行漏洞性能Rust比Node.js快得多尤其文件I/O、系统调用等场景体积Rust编译的二进制文件很小静态链接无运行时依赖前端和Rust后端的通信Tauri用命令Command模式——前端调用命令Rust后端执行返回结果。// 前端TypeScript调用Rust命令 import { invoke } from tauri-apps/api; // 调用名为greet的命令传入参数 const result await invoke(greet, { name: World }); console.log(result); // Hello, World!// 后端Rust定义命令 #[tauri::command] fn greet(name: str) - String { format!(Hello, {}!, name) } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![greet]) .run(tauri::generate_context!()) .expect(error while running tauri application); }实战用Tauri 2.0 React构建Markdown编辑器第一步环境准备Tauri需要系统安装Rust WebKit开发包。macOS# 安装Rust curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh # 安装Tauri依赖Xcode Command Line Tools xcode-select --installWindows# 安装Visual Studio 2022勾选使用C的桌面开发 # 安装WebPView2通常已预装 # 安装Rusthttps://www.rust-lang.org/tools/install第二步创建Tauri项目# 方式一用Tauri CLI推荐 npm create tauri-applatest # 回答提示 # Project name: markdown-editor # Frontend dev: React (TypeScript) # Package manager: npm # UI template: TypeScript Vite cd markdown-editor npm install第三步实现Markdown编辑器核心功能前端React CodeMirror// src/App.tsx import { useState, useEffect } from react; import CodeMirror from uiw/react-codemirror; import { markdown } from codemirror/lang-markdown; import { invoke } from tauri-apps/api; import { readTextFile, writeTextFile } from tauri-apps/api/fs; function App() { const [content, setContent] useState(# Hello Markdown); const [currentFile, setCurrentFile] useStatestring | null(null); // 保存文件调用Rust命令 async function saveFile() { if (currentFile) { await writeTextFile(currentFile, content); } else { // 调用系统文件对话框Tauri API const filePath await invoke(open_save_dialog); if (filePath) { await writeTextFile(filePath, content); setCurrentFile(filePath); } } } // 打开文件 async function openFile() { const filePath await invoke(open_open_dialog); if (filePath) { const text await readTextFile(filePath); setContent(text); setCurrentFile(filePath); } } return ( div classNameh-screen flex flex-col {/* 工具栏 */} div classNamebg-gray-100 p-2 flex gap-2 button onClick{openFile} classNamepx-4 py-1 bg-blue-600 text-white rounded 打开 /button button onClick{saveFile} classNamepx-4 py-1 bg-green-600 text-white rounded 保存 /button /div {/* 编辑器 */} div classNameflex-1 flex {/* 编辑区 */} div classNamew-1/2 border-r CodeMirror value{content} height100% extensions{[markdown()]} onChange{(val) setContent(val)} / /div {/* 预览区 */} div classNamew-1/2 p-4 prose max-w-none {/* 用markdown-it或remark渲染预览 */} div dangerouslySetInnerHTML{{ __html: renderMarkdown(content) }} / /div /div /div ); }后端Rust系统文件对话框Tauri的前端APItauri-apps/api/fs已经提供了readTextFile和writeTextFile但文件对话框需要用Rust命令封装因为需要调用系统原生对话框。// src/main.rs use tauri::Manager; // 打开文件对话框 #[tauri::command] async fn open_open_dialog() - ResultOptionString, String { let dialog tauri::api::dialog::FileDialogBuilder::new(); let file_path dialog .add_filter(Markdown Files, [md, markdown]) .pick_file() .await; Ok(file_path.map(|p| p.to_string_lossy().to_string())) } // 保存文件对话框 #[tauri::command] async fn open_save_dialog() - ResultOptionString, String { let dialog tauri::api::dialog::FileDialogBuilder::new(); let file_path dialog .add_filter(Markdown Files, [md, markdown]) .set_file_name(untitled.md) .save_file() .await; Ok(file_path.map(|p| p.to_string_lossy().to_string())) } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![ open_open_dialog, open_save_dialog ]) .run(tauri::generate_context!()) .expect(error while running tauri application); }系统托盘System Tray和全局快捷键桌面应用常用系统托盘菜单栏图标和全局快捷键即使应用在后台也能响应。实现系统托盘Tauri 2.0// src/main.ts (Tauri的生命周期脚本) import { TrayIcon } from tauri-apps/api/tray; import { getCurrentWindow } from tauri-apps/api/window; export async function setupTray() { const tray await TrayIcon.new({ iconPath: icons/icon.png, menu: [ { id: open, text: 打开主窗口, action: () { getCurrentWindow().show(); }, }, { id: quit, text: 退出, action: () { import(tauri-apps/api/process).then(m m.exit(0)); }, }, ], }); }实现全局快捷键// src/main.rs use tauri::GlobalShortcutManager; fn main() { tauri::Builder::default() .setup(|app| { let handle app.handle(); let shortcut_manager handle.global_shortcut_manager(); // 注册全局快捷键 CmdOrCtrlShiftP shortcut_manager .register(CmdOrCtrlShiftP, move || { let window handle.get_window(main).unwrap(); if window.is_visible().unwrap() { window.hide().unwrap(); } else { window.show().unwrap(); window.set_focus().unwrap(); } }) .unwrap(); Ok(()) }) .run(tauri::generate_context!()) .expect(error while running tauri application); }打包与分发自动更新和签名打包各平台# macOS需要Apple Developer ID签名 npm run tauri build -- --target universal-apple-darwin # Windows需要自签名或购买代码签名证书 npm run tauri build -- --target x86_64-pc-windows-msvc # Linux npm run tauri build -- --target x86_64-unknown-linux-gnu自动更新Tauri UpdaterTauri内置了自动更新功能。你需要把更新包上传到服务器或用GitHub Releases生成updater.json描述最新版本和下载URL在应用里配置每24小时检查一次更新// tauri.conf.json { tauri: { updater: { active: true, endpoints: [ https://yourserver.com/updater.json ], dialog: true, pubkey: your_public_key_here } } }结论Tauri 2.0适合你吗✅适合场景需要小体积、低内存的桌面应用如工具类、实用类对安全性有要求Rust的内存安全熟悉Rust或愿意学Rust❌不适合场景需要复杂的系统级API调用Electron的Node.js生态更丰富团队不熟悉Rust学习曲线较陡需要支持非常老的操作系统版本WebView2需要Windows 10独立开发者的实战建议如果你要做跨平台桌面应用先评估Electron能不能接受。如果能接受120MB的体积Electron的生态系统如electron-builder、electron-store更成熟。如果不能接受Tauri 2.0是目前最好的选择——小体积、高性能、现代化开发体验。下一步把你的Web应用如Next.js产品用Tauri打包成桌面应用——这让Web应用能访问文件系统、系统托盘、全局快捷键显著提升用户体验。