Skip to content

Tauri 核心架构

架构概述

┌─────────────────────────────────────────────────────┐
│                    Frontend (Web)                    │
│         HTML / CSS / JavaScript / Framework          │
│              (React / Vue / Svelte / Solid)          │
└─────────────────────────┬───────────────────────────┘
                          │ IPC (JSON-RPC)
┌─────────────────────────▼───────────────────────────┐
│                    Tauri Core                        │
│  ┌─────────────────────────────────────────────────┐│
│  │                  Rust Backend                   ││
│  │  Commands | Events | State | Plugins            ││
│  └─────────────────────────────────────────────────┘│
│  ┌─────────────────────────────────────────────────┐│
│  │               System WebView                    ││
│  │  macOS: WKWebView | Windows: WebView2 | Linux  ││
│  └─────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘

与 Electron 对比

特性TauriElectron
后端语言RustNode.js
渲染引擎系统 WebViewChromium
包体积~3-10 MB~150+ MB
内存占用
安全性高(Rust + 权限系统)
生态成长中成熟

IPC 通信

定义 Command

rust
// src-tauri/src/main.rs
use tauri::command;

#[command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

#[command]
async fn fetch_data(url: String) -> Result<String, String> {
    reqwest::get(&url)
        .await
        .map_err(|e| e.to_string())?
        .text()
        .await
        .map_err(|e| e.to_string())
}

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

前端调用

typescript
import { invoke } from '@tauri-apps/api/core';

// 同步风格调用
const greeting = await invoke<string>('greet', { name: 'World' });

// 异步操作
try {
  const data = await invoke<string>('fetch_data', { 
    url: 'https://api.example.com/data' 
  });
  console.log(data);
} catch (error) {
  console.error('Failed to fetch:', error);
}

事件系统

Rust 端发送事件

rust
use tauri::{AppHandle, Manager};

#[command]
fn start_download(app: AppHandle, url: String) {
    std::thread::spawn(move || {
        for progress in 0..=100 {
            app.emit("download-progress", progress).unwrap();
            std::thread::sleep(std::time::Duration::from_millis(50));
        }
        app.emit("download-complete", ()).unwrap();
    });
}

前端监听事件

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

// 监听事件
const unlisten = await listen<number>('download-progress', (event) => {
  console.log(`Progress: ${event.payload}%`);
});

// 监听一次性事件
await once('download-complete', () => {
  console.log('Download finished!');
});

// 取消监听
unlisten();

状态管理

rust
use std::sync::Mutex;
use tauri::State;

// 定义应用状态
struct AppState {
    counter: Mutex<i32>,
    config: Mutex<Config>,
}

#[command]
fn increment(state: State<AppState>) -> i32 {
    let mut counter = state.counter.lock().unwrap();
    *counter += 1;
    *counter
}

fn main() {
    tauri::Builder::default()
        .manage(AppState {
            counter: Mutex::new(0),
            config: Mutex::new(Config::default()),
        })
        .invoke_handler(tauri::generate_handler![increment])
        .run(tauri::generate_context!())
        .unwrap();
}

插件系统

使用官方插件

toml
# Cargo.toml
[dependencies]
tauri-plugin-store = "2"
tauri-plugin-shell = "2"
tauri-plugin-fs = "2"
rust
fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_store::Builder::new().build())
        .plugin(tauri_plugin_shell::init())
        .plugin(tauri_plugin_fs::init())
        .run(tauri::generate_context!())
        .unwrap();
}

前端使用插件

typescript
import { Store } from '@tauri-apps/plugin-store';

const store = await Store.load('settings.json');
await store.set('theme', 'dark');
const theme = await store.get<string>('theme');
await store.save();

窗口管理

rust
use tauri::{Manager, WindowBuilder, WindowUrl};

#[command]
async fn open_settings(app: AppHandle) -> Result<(), String> {
    let _settings_window = WindowBuilder::new(
        &app,
        "settings",
        WindowUrl::App("settings.html".into())
    )
    .title("Settings")
    .inner_size(600.0, 400.0)
    .resizable(false)
    .build()
    .map_err(|e| e.to_string())?;
    
    Ok(())
}
typescript
import { Window } from '@tauri-apps/api/window';

// 获取当前窗口
const mainWindow = Window.getCurrent();

// 窗口操作
await mainWindow.minimize();
await mainWindow.maximize();
await mainWindow.setTitle('New Title');
await mainWindow.center();

面试要点

  1. 架构优势:Rust 后端 + 系统 WebView = 小体积低内存
  2. IPC 机制:Commands (请求-响应) + Events (发布-订阅)
  3. 安全模型:权限白名单、CSP、Rust 内存安全
  4. 与 Electron 对比:体积、性能、生态成熟度

前端面试知识库