tauri
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTauri 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: Usewith technology:mcp__documentation__fetch_docsfor comprehensive API documentation.tauri
完整参考:查看 advanced.md 了解事件系统、插件(对话框、文件系统、存储)、打包配置、代码签名、测试模式和输入验证相关内容。
深度知识:调用并指定技术栈为mcp__documentation__fetch_docs可获取完整的API文档。tauri
When NOT to Use This Skill
该技能不适用的场景
- Electron applications - Use the skill
electron - 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应用:请使用skill
electron - 纯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.tstauri-app/
├── src/ # 前端源码
│ └── routes/
├── src-tauri/ # Rust后端
│ ├── Cargo.toml
│ ├── tauri.conf.json
│ ├── capabilities/ # 权限配置
│ └── src/
│ ├── main.rs
│ └── lib.rs
├── package.json
└── vite.config.tsConfiguration
配置
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-Pattern | Why It's Wrong | Correct Approach |
|---|---|---|
| No input validation in commands | Vulnerable to injection | Validate all parameters |
Using | Panics crash the app | Use |
| Exposing all filesystem | Security risk | Use scoped permissions |
| Synchronous blocking in commands | Freezes UI | Use |
| Not using State for shared data | Data races | Use |
| Hardcoding paths | Breaks cross-platform | Use |
| Defeats security model | List required permissions |
| 反模式 | 错误原因 | 正确做法 |
|---|---|---|
| 命令中没有输入验证 | 存在注入攻击风险 | 验证所有传入参数 |
命令中使用 | 恐慌会导致应用崩溃 | 使用 |
| 开放全文件系统权限 | 存在安全风险 | 使用作用域权限控制 |
| 命令中使用同步阻塞逻辑 | 会导致UI卡顿 | 使用 |
| 共享数据不使用State管理 | 会出现数据竞争 | 使用带Mutex的 |
| 硬编码路径 | 跨平台运行异常 | 使用 |
权限配置为 | 破坏安全模型 | 仅列出所需的权限 |
Quick Troubleshooting
快速故障排查
| Issue | Diagnosis | Solution |
|---|---|---|
| "Command not found" | Not registered | Add to |
| V2 uses capabilities | Migrate to |
| Frontend can't read file | Missing permissions | Add |
| Dev server not running | Check |
| IPC calls are slow | Large payload | Minimize data transfer |
| App crashes on state access | State not initialized | Register with |
| 问题 | 诊断 | 解决方案 |
|---|---|---|
| 提示"Command not found" | 命令未注册 | 添加到 |
v2版本后出现 | V2版本使用能力权限体系 | 迁移到 |
| 前端无法读取文件 | 缺少对应权限 | 添加 |
| 开发服务未正常运行 | 检查 |
| IPC调用速度慢 | 传输数据量过大 | 减少数据传输体积 |
| 访问状态时应用崩溃 | 状态未初始化 | 使用 |
Quick Reference
快速参考
- Commands Cheatsheet
- Plugins Cheatsheet
- 命令速查表
- 插件速查表