Tauri框架初探:用Rust写桌面应用

Tauri是一个用Rust编写的轻量级桌面应用框架,前端用Web技术,后端用Rust——与Electron相比,打包体积和内存占用可以降低一个数量级。

1. Tauri vs Electron

先看核心对比数据:

指标 Tauri Electron
Hello World安装包大小 ~3 MB ~85 MB
运行内存占用 ~30 MB ~150 MB
后端语言 Rust Node.js
渲染引擎 系统WebView 自带Chromium
安全模型 默认最小权限 完整Node.js权限

Tauri使用操作系统自带的WebView(Windows上是WebView2/Edge,macOS是WKWebView,Linux是WebKitGTK),所以不需要打包整个Chromium。这也是它体积小的根本原因。

缺点是跨平台渲染一致性不如Electron,某些CSS特性在不同系统的WebView上表现可能有差异。

2. 项目初始化

前置条件

  • Rust工具链(rustup安装)
  • Node.js 16+
  • 系统依赖:
    • Windows:WebView2(Win10/11自带)
    • macOS:Xcode Command Line Tools
    • Linux:libwebkit2gtk-4.0-dev, libgtk-3-dev

创建项目

# 使用官方脚手架
npm create tauri-app@latest

# 按提示选择:
# Project name: my-tauri-app
# Frontend framework: Vanilla / React / Vue / Svelte
# (以React为例)

生成的项目结构:

my-tauri-app/
├── src/                 # 前端代码(React)
│   ├── App.tsx
│   └── main.tsx
├── src-tauri/           # Rust后端代码
│   ├── src/
│   │   └── main.rs      # Rust入口
│   ├── Cargo.toml
│   └── tauri.conf.json  # Tauri配置
├── package.json
└── vite.config.ts

启动开发服务器:

npm run tauri dev

第一次运行会编译Rust代码,稍等片刻后会弹出桌面窗口,内嵌了前端页面。支持前端热更新(HMR),Rust代码修改后也会自动重新编译。

3. 前端 + Rust后端架构

Tauri的架构很清晰:

┌──────────────────────────────┐
│  Desktop Window              │
│  ┌────────────────────────┐  │
│  │  WebView (系统自带)     │  │
│  │  ┌──────────────────┐  │  │
│  │  │  前端 (React等)   │  │  │
│  │  │  HTML/CSS/JS     │  │  │
│  │  └───────┬──────────┘  │  │
│  │          │ invoke()     │  │
│  │          ▼              │  │
│  │  ┌──────────────────┐  │  │
│  │  │  Rust Core       │  │  │
│  │  │  (文件/网络/系统) │  │  │
│  │  └──────────────────┘  │  │
│  └────────────────────────┘  │
└──────────────────────────────┘

前端通过invoke()函数调用Rust后端的命令。Rust处理文件操作、网络请求、系统调用等需要原生能力的任务。

4. #[tauri::command] —— 前后端通信

定义一个Rust命令:

// src-tauri/src/main.rs
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! This is from Rust.", name)
}

fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

前端调用:

import { invoke } from "@tauri-apps/api/tauri";

async function callRust() {
    const result = await invoke<string>("greet", { name: "World" });
    console.log(result); // "Hello, World! This is from Rust."
}

参数和返回值自动通过JSON序列化/反序列化。复杂类型需要实现serde::Serialize/Deserialize

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct FileInfo {
    name: String,
    size: u64,
    is_dir: bool,
}

#[tauri::command]
fn list_dir(path: String) -> Result<Vec<FileInfo>, String> {
    let entries = std::fs::read_dir(&path)
        .map_err(|e| e.to_string())?;

    let mut files = Vec::new();
    for entry in entries {
        let entry = entry.map_err(|e| e.to_string())?;
        let metadata = entry.metadata().map_err(|e| e.to_string())?;
        files.push(FileInfo {
            name: entry.file_name().to_string_lossy().to_string(),
            size: metadata.len(),
            is_dir: metadata.is_dir(),
        });
    }
    Ok(files)
}

返回Result<T, String>时,Err会在前端变成rejected Promise。

5. 事件系统

除了command的请求-响应模式,Tauri还支持事件驱动通信:

Rust端发送事件:

use tauri::Manager;

#[tauri::command]
fn start_task(window: tauri::Window) {
    std::thread::spawn(move || {
        for i in 0..100 {
            std::thread::sleep(std::time::Duration::from_millis(50));
            window.emit("progress", i).unwrap();
        }
        window.emit("task-complete", "done").unwrap();
    });
}

前端监听事件:

import { listen } from "@tauri-apps/api/event";

await listen<number>("progress", (event) => {
    console.log(`Progress: ${event.payload}%`);
});

await listen<string>("task-complete", (event) => {
    console.log(`Task completed: ${event.payload}`);
});

事件系统适合长时间运行的后台任务(文件复制、下载进度等)。

6. 打包发布

npm run tauri build

输出在src-tauri/target/nelease/bundle/下:

  • Windows.msi安装包 和 .exe
  • macOS.dmg.app
  • Linux.deb.AppImage

tauri.conf.json中配置应用信息:

{
  "package": {
    "productName": "My App",
    "version": "1.0.0"
  },
  "tauri": {
    "bundle": {
      "identifier": "com.example.myapp",
      "icon": [
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/icon.ico"
      ]
    },
    "windows": [{
      "title": "My Tauri App",
      "width": 1024,
      "height": 768,
      "resizable": true
    }]
  }
}

小结

Tauri给Web前端开发者提供了一条通往原生桌面应用的轻量级路径。如果你的应用不需要像VS Code那样深度定制Chromium,Tauri在体积、性能和安全性上都优于Electron。学习成本主要在Rust,但对于简单的后端逻辑,上手门槛并不高。