tauri

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Tauri Core Knowledge

Tauri核心知识

Full Reference: See advanced.md for event system, plugins (Dialog, Filesystem, Store), bundling configuration, code signing, testing patterns, and input validation.
Deep Knowledge: Use
mcp__documentation__fetch_docs
with technology:
tauri
for comprehensive API documentation.
完整参考:查看 advanced.md 了解事件系统、插件(对话框、文件系统、存储)、打包配置、代码签名、测试模式和输入验证相关内容。
深度知识:调用
mcp__documentation__fetch_docs
并指定技术栈为
tauri
可获取完整的API文档。

When NOT to Use This Skill

该技能不适用的场景

  • Electron applications - Use the
    electron
    skill
  • Pure Rust applications - Use Rust skill for CLI or backend-only
  • Web-only deployments - Tauri is for desktop apps
  • Mobile apps - Tauri Mobile is in alpha
  • Applications requiring Node.js ecosystem - Use Electron
  • Electron应用:请使用
    electron
    skill
  • 纯Rust应用:CLI或纯后端相关问题请使用Rust skill
  • 纯Web部署场景:Tauri仅用于构建桌面应用
  • 移动应用:Tauri Mobile目前处于alpha阶段
  • 需要Node.js生态的应用:请使用Electron

Architecture

架构

┌─────────────────────────────────────────────────────────────┐
│                      Rust Backend                            │
│  • Tauri Runtime (window management, events, plugins)       │
│  • Custom Commands (#[tauri::command])                      │
│  • State Management (tauri::State with Mutex/RwLock)        │
└──────────────────────────┬──────────────────────────────────┘
                           │ IPC (invoke / events)
┌──────────────────────────▼──────────────────────────────────┐
│                   System WebView                             │
│  • Web APIs (DOM, CSS, JavaScript) - No Node.js             │
│  • @tauri-apps/api (type-safe IPC)                          │
│  • Frontend Framework (Svelte/React/Vue)                    │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                      Rust Backend                            │
│  • Tauri Runtime (窗口管理、事件、插件)                        │
│  • 自定义命令 (#[tauri::command])                            │
│  • 状态管理 (带Mutex/RwLock的tauri::State)                    │
└──────────────────────────┬──────────────────────────────────┘
                           │ IPC (调用 / 事件)
┌──────────────────────────▼──────────────────────────────────┐
│                   System WebView                             │
│  • Web APIs (DOM、CSS、JavaScript) - 无Node.js环境             │
│  • @tauri-apps/api (类型安全的IPC)                            │
│  • 前端框架 (Svelte/React/Vue)                                │
└─────────────────────────────────────────────────────────────┘

Project Structure

项目结构

tauri-app/
├── src/                        # Frontend source
│   └── routes/
├── src-tauri/                  # Rust backend
│   ├── Cargo.toml
│   ├── tauri.conf.json
│   ├── capabilities/           # Permissions
│   └── src/
│       ├── main.rs
│       └── lib.rs
├── package.json
└── vite.config.ts
tauri-app/
├── src/                        # 前端源码
│   └── routes/
├── src-tauri/                  # Rust后端
│   ├── Cargo.toml
│   ├── tauri.conf.json
│   ├── capabilities/           # 权限配置
│   └── src/
│       ├── main.rs
│       └── lib.rs
├── package.json
└── vite.config.ts

Configuration

配置

tauri.conf.json

tauri.conf.json

json
{
  "$schema": "https://schema.tauri.app/config/2",
  "productName": "My App",
  "version": "1.0.0",
  "identifier": "com.company.myapp",
  "build": {
    "beforeBuildCommand": "npm run build",
    "beforeDevCommand": "npm run dev",
    "devUrl": "http://localhost:5173",
    "frontendDist": "../build"
  },
  "app": {
    "windows": [{
      "title": "My App",
      "width": 1200,
      "height": 800,
      "center": true
    }],
    "security": {
      "csp": "default-src 'self'; script-src 'self'"
    }
  }
}

json
{
  "$schema": "https://schema.tauri.app/config/2",
  "productName": "My App",
  "version": "1.0.0",
  "identifier": "com.company.myapp",
  "build": {
    "beforeBuildCommand": "npm run build",
    "beforeDevCommand": "npm run dev",
    "devUrl": "http://localhost:5173",
    "frontendDist": "../build"
  },
  "app": {
    "windows": [{
      "title": "My App",
      "width": 1200,
      "height": 800,
      "center": true
    }],
    "security": {
      "csp": "default-src 'self'; script-src 'self'"
    }
  }
}

IPC Communication

IPC通信

Basic Command

基础命令

rust
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
typescript
// Frontend
import { invoke } from '@tauri-apps/api/core';

const message = await invoke<string>('greet', { name: 'World' });
rust
// src-tauri/src/lib.rs
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
typescript
// 前端代码
import { invoke } from '@tauri-apps/api/core';

const message = await invoke<string>('greet', { name: 'World' });

Async Command with Error Handling

带错误处理的异步命令

rust
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize)]
pub struct CommandError {
    pub code: String,
    pub message: String,
}

#[derive(Serialize, Deserialize)]
pub struct User {
    id: u32,
    name: String,
    email: String,
}

#[tauri::command]
async fn get_user(id: u32) -> Result<User, CommandError> {
    if id == 0 {
        return Err(CommandError {
            code: "NOT_FOUND".to_string(),
            message: "User not found".to_string(),
        });
    }

    Ok(User {
        id,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
    })
}
typescript
interface CommandError {
  code: string;
  message: string;
}

try {
  const user = await invoke<User>('get_user', { id: 1 });
} catch (error) {
  const err = error as CommandError;
  console.error(`[${err.code}] ${err.message}`);
}
rust
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize)]
pub struct CommandError {
    pub code: String,
    pub message: String,
}

#[derive(Serialize, Deserialize)]
pub struct User {
    id: u32,
    name: String,
    email: String,
}

#[tauri::command]
async fn get_user(id: u32) -> Result<User, CommandError> {
    if id == 0 {
        return Err(CommandError {
            code: "NOT_FOUND".to_string(),
            message: "User not found".to_string(),
        });
    }

    Ok(User {
        id,
        name: "Alice".to_string(),
        email: "alice@example.com".to_string(),
    })
}
typescript
interface CommandError {
  code: string;
  message: string;
}

try {
  const user = await invoke<User>('get_user', { id: 1 });
} catch (error) {
  const err = error as CommandError;
  console.error(`[${err.code}] ${err.message}`);
}

State Management

状态管理

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

pub struct AppState {
    pub counter: Mutex<i32>,
}

#[tauri::command]
fn get_count(state: State<AppState>) -> i32 {
    *state.counter.lock().unwrap()
}

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

// In main
tauri::Builder::default()
    .manage(AppState { counter: Mutex::new(0) })
    .invoke_handler(tauri::generate_handler![get_count, increment])

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

pub struct AppState {
    pub counter: Mutex<i32>,
}

#[tauri::command]
fn get_count(state: State<AppState>) -> i32 {
    *state.counter.lock().unwrap()
}

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

// 主函数中注册
tauri::Builder::default()
    .manage(AppState { counter: Mutex::new(0) })
    .invoke_handler(tauri::generate_handler![get_count, increment])

Security

安全

Capability-Based Permissions

基于能力的权限体系

json
// src-tauri/capabilities/default.json
{
  "identifier": "default",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "dialog:allow-open",
    "dialog:allow-save",
    "fs:allow-read-text-file",
    "fs:allow-write-text-file",
    {
      "identifier": "fs:scope",
      "allow": ["$APPDATA/**", "$DOCUMENT/**"]
    },
    "store:default"
  ]
}

json
// src-tauri/capabilities/default.json
{
  "identifier": "default",
  "windows": ["main"],
  "permissions": [
    "core:default",
    "dialog:allow-open",
    "dialog:allow-save",
    "fs:allow-read-text-file",
    "fs:allow-write-text-file",
    {
      "identifier": "fs:scope",
      "allow": ["$APPDATA/**", "$DOCUMENT/**"]
    },
    "store:default"
  ]
}

Anti-Patterns

反模式

Anti-PatternWhy It's WrongCorrect Approach
No input validation in commandsVulnerable to injectionValidate all parameters
Using
.unwrap()
in commands
Panics crash the appUse
Result<T, E>
Exposing all filesystemSecurity riskUse scoped permissions
Synchronous blocking in commandsFreezes UIUse
async
functions
Not using State for shared dataData racesUse
tauri::State
with Mutex
Hardcoding pathsBreaks cross-platformUse
BaseDirectory
enum
allow-all
in permissions
Defeats security modelList required permissions
反模式错误原因正确做法
命令中没有输入验证存在注入攻击风险验证所有传入参数
命令中使用
.unwrap()
恐慌会导致应用崩溃使用
Result<T, E>
处理错误
开放全文件系统权限存在安全风险使用作用域权限控制
命令中使用同步阻塞逻辑会导致UI卡顿使用
async
异步函数
共享数据不使用State管理会出现数据竞争使用带Mutex的
tauri::State
硬编码路径跨平台运行异常使用
BaseDirectory
枚举
权限配置为
allow-all
破坏安全模型仅列出所需的权限

Quick Troubleshooting

快速故障排查

IssueDiagnosisSolution
"Command not found"Not registeredAdd to
generate_handler![]
allowlist
errors after v2
V2 uses capabilitiesMigrate to
capabilities/
Frontend can't read fileMissing permissionsAdd
fs:allow-read-*
tauri dev
shows blank window
Dev server not runningCheck
devUrl
matches
IPC calls are slowLarge payloadMinimize data transfer
App crashes on state accessState not initializedRegister with
.manage()
问题诊断解决方案
提示"Command not found"命令未注册添加到
generate_handler![]
数组中
v2版本后出现
allowlist
错误
V2版本使用能力权限体系迁移到
capabilities/
配置目录
前端无法读取文件缺少对应权限添加
fs:allow-read-*
权限
tauri dev
显示空白窗口
开发服务未正常运行检查
devUrl
配置是否匹配
IPC调用速度慢传输数据量过大减少数据传输体积
访问状态时应用崩溃状态未初始化使用
.manage()
注册状态

Quick Reference

快速参考

  • Commands Cheatsheet
  • Plugins Cheatsheet
  • 命令速查表
  • 插件速查表