integrating-tauri-rust-frontends
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTauri Rust/WASM Frontend Integration
Tauri Rust/WASM 前端集成
This skill covers integrating Rust-based frontend frameworks with Tauri v2 for building desktop and mobile applications with WASM.
本内容介绍如何将基于Rust的前端框架与Tauri v2集成,以构建基于WASM的桌面和移动应用。
Supported Frameworks
支持的框架
| Framework | Description | Bundler |
|---|---|---|
| Leptos | Reactive Rust framework for building web UIs | Trunk |
| Yew | Component-based Rust framework | Trunk |
| Dioxus | Cross-platform UI framework | Trunk |
| Sycamore | Reactive library for Rust | Trunk |
All Rust/WASM frontends use Trunk as the bundler/dev server.
| 框架 | 描述 | 打包工具 |
|---|---|---|
| Leptos | 用于构建Web UI的响应式Rust框架 | Trunk |
| Yew | 基于组件的Rust框架 | Trunk |
| Dioxus | 跨平台UI框架 | Trunk |
| Sycamore | Rust响应式库 | Trunk |
所有Rust/WASM前端均使用 Trunk 作为打包工具/开发服务器。
Critical Requirements
关键要求
- Static Site Generation (SSG) Only - Tauri does not support server-based solutions (SSR). Use SSG, SPA, or MPA approaches.
- withGlobalTauri - Must be enabled for WASM frontends to access Tauri APIs via and
window.__TAURI__.wasm-bindgen - WebSocket Protocol - Configure for hot-reload on mobile development.
ws_protocol = "ws"
- 仅支持静态站点生成(SSG) - Tauri不支持基于服务器的方案(SSR)。请使用SSG、SPA或MPA方式。
- withGlobalTauri - 必须启用该配置,WASM前端才能通过和
window.__TAURI__访问Tauri API。wasm-bindgen - WebSocket协议 - 移动端开发热重载需配置。
ws_protocol = "ws"
Project Structure
项目结构
my-tauri-app/
├── src/
│ ├── main.rs # Rust frontend entry point
│ └── app.rs # Application component
├── src-tauri/
│ ├── src/
│ │ └── main.rs # Tauri backend
│ ├── Cargo.toml # Tauri dependencies
│ └── tauri.conf.json # Tauri configuration
├── index.html # HTML entry point for Trunk
├── Cargo.toml # Frontend dependencies
├── Trunk.toml # Trunk bundler configuration
└── dist/ # Build output (generated)my-tauri-app/
├── src/
│ ├── main.rs # Rust前端入口文件
│ └── app.rs # 应用组件
├── src-tauri/
│ ├── src/
│ │ └── main.rs # Tauri后端
│ ├── Cargo.toml # Tauri依赖
│ └── tauri.conf.json # Tauri配置
├── index.html # Trunk的HTML入口文件
├── Cargo.toml # 前端依赖
├── Trunk.toml # Trunk打包工具配置
└── dist/ # 构建输出(自动生成)Configuration Files
配置文件
Tauri Configuration (src-tauri/tauri.conf.json)
Tauri配置(src-tauri/tauri.conf.json)
json
{
"build": {
"beforeDevCommand": "trunk serve",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "trunk build",
"frontendDist": "../dist"
},
"app": {
"withGlobalTauri": true
}
}Key settings:
- : Runs Trunk dev server before Tauri
beforeDevCommand - : URL where Trunk serves the frontend (default: 1420 for Leptos, 8080 for plain Trunk)
devUrl - : Builds WASM bundle before packaging
beforeBuildCommand - : Path to built frontend assets
frontendDist - : Required for WASM - Exposes
withGlobalTaurifor API accesswindow.__TAURI__
json
{
"build": {
"beforeDevCommand": "trunk serve",
"devUrl": "http://localhost:1420",
"beforeBuildCommand": "trunk build",
"frontendDist": "../dist"
},
"app": {
"withGlobalTauri": true
}
}关键设置:
- : 在启动Tauri前运行Trunk开发服务器
beforeDevCommand - : Trunk提供前端服务的URL(Leptos默认端口1420,纯Trunk默认8080)
devUrl - : 打包前构建WASM包
beforeBuildCommand - : 已构建前端资源的路径
frontendDist - : WASM必选配置 - 暴露
withGlobalTauri以访问APIwindow.__TAURI__
Trunk Configuration (Trunk.toml)
Trunk配置(Trunk.toml)
toml
[build]
target = "./index.html"
dist = "./dist"
[watch]
ignore = ["./src-tauri"]
[serve]
port = 1420
open = false
[serve.ws]
ws_protocol = "ws"Key settings:
- : HTML entry point with Trunk directives
target - : Prevents watching Tauri backend changes
ignore - : Must match
portin tauri.conf.jsondevUrl - : Prevents browser auto-open (Tauri handles display)
open = false - : Required for mobile hot-reload
ws_protocol = "ws"
toml
[build]
target = "./index.html"
dist = "./dist"
[watch]
ignore = ["./src-tauri"]
[serve]
port = 1420
open = false
[serve.ws]
ws_protocol = "ws"关键设置:
- : 包含Trunk指令的HTML入口文件
target - : 避免监听Tauri后端的变更
ignore - : 必须与tauri.conf.json中的
port端口匹配devUrl - : 阻止浏览器自动打开(由Tauri负责显示)
open = false - : 移动端热重载必选配置
ws_protocol = "ws"
Frontend Cargo.toml (Root)
前端Cargo.toml(根目录)
toml
[package]
name = "my-app-frontend"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]toml
[package]
name = "my-app-frontend"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]Core WASM dependencies
核心WASM依赖
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["Window", "Document"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["Window", "Document"] }
Tauri API bindings for WASM
用于WASM的Tauri API绑定
tauri-wasm = { version = "2", features = ["all"] }
tauri-wasm = { version = "2", features = ["all"] }
Choose your framework:
选择你的框架:
For Leptos:
对于Leptos:
leptos = { version = "0.6", features = ["csr"] }
leptos = { version = "0.6", features = ["csr"] }
For Yew:
对于Yew:
yew = { version = "0.21", features = ["csr"] }
yew = { version = "0.21", features = ["csr"] }
For Dioxus:
对于Dioxus:
dioxus = { version = "0.5", features = ["web"] }
dioxus = { version = "0.5", features = ["web"] }
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
**Key settings:**
- `crate-type = ["cdylib", "rlib"]`: Required for WASM compilation
- `tauri-wasm`: Provides Rust bindings to Tauri APIs
- `features = ["csr"]`: Client-side rendering for framework
- Release profile optimized for small WASM binary size[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
**关键设置:**
- `crate-type = ["cdylib", "rlib"]`: WASM编译必选配置
- `tauri-wasm`: 提供Tauri API的Rust绑定
- `features = ["csr"]`: 框架的客户端渲染模式
- Release配置针对WASM二进制大小优化HTML Entry Point (index.html)
HTML入口文件(index.html)
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Tauri App</title>
<link data-trunk rel="css" href="styles.css" />
</head>
<body>
<div id="app"></div>
<link data-trunk rel="rust" href="." data-wasm-opt="z" />
</body>
</html>Trunk directives:
- : Include CSS files
data-trunk rel="css" - : Compile Rust crate to WASM
data-trunk rel="rust" - : Optimize for size
data-wasm-opt="z"
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My Tauri App</title>
<link data-trunk rel="css" href="styles.css" />
</head>
<body>
<div id="app"></div>
<link data-trunk rel="rust" href="." data-wasm-opt="z" />
</body>
</html>Trunk指令:
- : 引入CSS文件
data-trunk rel="css" - : 将Rust crate编译为WASM
data-trunk rel="rust" - : 针对大小进行优化
data-wasm-opt="z"
Leptos Setup
Leptos 设置
Leptos-Specific Cargo.toml
Leptos专属Cargo.toml
toml
[package]
name = "my-leptos-app"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
leptos = { version = "0.6", features = ["csr"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
console_error_panic_hook = "0.1"
tauri-wasm = { version = "2", features = ["all"] }
[profile.release]
opt-level = "z"
lto = truetoml
[package]
name = "my-leptos-app"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
leptos = { version = "0.6", features = ["csr"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
console_error_panic_hook = "0.1"
tauri-wasm = { version = "2", features = ["all"] }
[profile.release]
opt-level = "z"
lto = trueLeptos Main Entry (src/main.rs)
Leptos主入口(src/main.rs)
rust
use leptos::*;
mod app;
use app::App;
fn main() {
console_error_panic_hook::set_once();
mount_to_body(|| view! { <App /> });
}rust
use leptos::*;
mod app;
use app::App;
fn main() {
console_error_panic_hook::set_once();
mount_to_body(|| view! { <App /> });
}Leptos App Component (src/app.rs)
Leptos应用组件(src/app.rs)
rust
use leptos::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}
#[component]
pub fn App() -> impl IntoView {
let (message, set_message) = create_signal(String::new());
let greet = move |_| {
spawn_local(async move {
let args = serde_json::json!({ "name": "World" });
let args_js = serde_wasm_bindgen::to_value(&args).unwrap();
let result = invoke("greet", args_js).await;
let greeting: String = serde_wasm_bindgen::from_value(result).unwrap();
set_message.set(greeting);
});
};
view! {
<main>
<h1>"Welcome to Tauri + Leptos"</h1>
<button on:click=greet>"Greet"</button>
<p>{message}</p>
</main>
}
}rust
use leptos::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"])]
async fn invoke(cmd: &str, args: JsValue) -> JsValue;
}
#[component]
pub fn App() -> impl IntoView {
let (message, set_message) = create_signal(String::new());
let greet = move |_| {
spawn_local(async move {
let args = serde_json::json!({ "name": "World" });
let args_js = serde_wasm_bindgen::to_value(&args).unwrap();
let result = invoke("greet", args_js).await;
let greeting: String = serde_wasm_bindgen::from_value(result).unwrap();
set_message.set(greeting);
});
};
view! {
<main>
<h1>"Welcome to Tauri + Leptos"</h1>
<button on:click=greet>"Greet"</button>
<p>{message}</p>
</main>
}
}Alternative: Using tauri-wasm Crate
替代方案:使用tauri-wasm库
rust
use leptos::*;
use tauri_wasm::api::core::invoke;
#[component]
pub fn App() -> impl IntoView {
let (message, set_message) = create_signal(String::new());
let greet = move |_| {
spawn_local(async move {
let result: String = invoke("greet", &serde_json::json!({ "name": "World" }))
.await
.unwrap();
set_message.set(result);
});
};
view! {
<main>
<button on:click=greet>"Greet"</button>
<p>{message}</p>
</main>
}
}rust
use leptos::*;
use tauri_wasm::api::core::invoke;
#[component]
pub fn App() -> impl IntoView {
let (message, set_message) = create_signal(String::new());
let greet = move |_| {
spawn_local(async move {
let result: String = invoke("greet", &serde_json::json!({ "name": "World" }))
.await
.unwrap();
set_message.set(result);
});
};
view! {
<main>
<button on:click=greet>"Greet"</button>
<p>{message}</p>
</main>
}
}Tauri Backend Command
Tauri 后端命令
In :
src-tauri/src/main.rsrust
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}在中:
src-tauri/src/main.rsrust
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}Development Commands
开发命令
bash
undefinedbash
undefinedInstall Trunk
安装Trunk
cargo install trunk
cargo install trunk
Add WASM target
添加WASM目标
rustup target add wasm32-unknown-unknown
rustup target add wasm32-unknown-unknown
Development (runs Trunk + Tauri)
开发模式(运行Trunk + Tauri)
cd src-tauri && cargo tauri dev
cd src-tauri && cargo tauri dev
Build for production
生产构建
cd src-tauri && cargo tauri build
cd src-tauri && cargo tauri build
Trunk only (for frontend debugging)
仅启动Trunk(用于前端调试)
trunk serve --port 1420
trunk serve --port 1420
Build WASM only
仅构建WASM
trunk build --release
undefinedtrunk build --release
undefinedMobile Development
移动端开发
For mobile platforms, additional configuration is needed:
针对移动平台,需要额外配置:
Trunk.toml for Mobile
移动端Trunk.toml
toml
[serve]
port = 1420
open = false
address = "0.0.0.0" # Listen on all interfaces for mobile
[serve.ws]
ws_protocol = "ws" # Required for mobile hot-reloadtoml
[serve]
port = 1420
open = false
address = "0.0.0.0" # 监听所有接口以支持移动端访问
[serve.ws]
ws_protocol = "ws" # 移动端热重载必选配置tauri.conf.json for Mobile
移动端tauri.conf.json
json
{
"build": {
"beforeDevCommand": "trunk serve --address 0.0.0.0",
"devUrl": "http://YOUR_LOCAL_IP:1420"
}
}Replace with your machine's local IP (e.g., ).
YOUR_LOCAL_IP192.168.1.100json
{
"build": {
"beforeDevCommand": "trunk serve --address 0.0.0.0",
"devUrl": "http://YOUR_LOCAL_IP:1420"
}
}将替换为你的机器本地IP(例如:)。
YOUR_LOCAL_IP192.168.1.100Accessing Tauri APIs from WASM
从WASM访问Tauri API
Method 1: Direct wasm-bindgen (Recommended for control)
方法1:直接使用wasm-bindgen(推荐用于精细控制)
rust
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
#[wasm_bindgen]
extern "C" {
// Core invoke
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], catch)]
async fn invoke(cmd: &str, args: JsValue) -> Result<JsValue, JsValue>;
// Event system
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "event"])]
async fn listen(event: &str, handler: &Closure<dyn Fn(JsValue)>) -> JsValue;
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "event"])]
async fn emit(event: &str, payload: JsValue);
}
// Usage
async fn call_backend() -> Result<String, String> {
let args = serde_wasm_bindgen::to_value(&serde_json::json!({
"path": "/some/path"
})).map_err(|e| e.to_string())?;
let result = invoke("read_file", args)
.await
.map_err(|e| format!("{:?}", e))?;
serde_wasm_bindgen::from_value(result)
.map_err(|e| e.to_string())
}rust
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
#[wasm_bindgen]
extern "C" {
// 核心invoke方法
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "core"], catch)]
async fn invoke(cmd: &str, args: JsValue) -> Result<JsValue, JsValue>;
// 事件系统
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "event"])]
async fn listen(event: &str, handler: &Closure<dyn Fn(JsValue)>) -> JsValue;
#[wasm_bindgen(js_namespace = ["window", "__TAURI__", "event"])]
async fn emit(event: &str, payload: JsValue);
}
// 使用示例
async fn call_backend() -> Result<String, String> {
let args = serde_wasm_bindgen::to_value(&serde_json::json!({
"path": "/some/path"
})).map_err(|e| e.to_string())?;
let result = invoke("read_file", args)
.await
.map_err(|e| format!("{:?}", e))?;
serde_wasm_bindgen::from_value(result)
.map_err(|e| e.to_string())
}Method 2: Using tauri-wasm Crate
方法2:使用tauri-wasm库
rust
use tauri_wasm::api::{core, event, dialog, fs};
// Invoke command
let result: MyResponse = core::invoke("my_command", &my_args).await?;
// Listen to events
event::listen("my-event", |payload| {
// Handle event
}).await;
// Emit events
event::emit("my-event", &payload).await;
// File dialogs
let file = dialog::open(dialog::OpenDialogOptions::default()).await?;
// File system (requires permissions)
let contents = fs::read_text_file("path/to/file").await?;rust
use tauri_wasm::api::{core, event, dialog, fs};
// 调用命令
let result: MyResponse = core::invoke("my_command", &my_args).await?;
// 监听事件
event::listen("my-event", |payload| {
// 处理事件
}).await;
// 发送事件
event::emit("my-event", &payload).await;
// 文件对话框
let file = dialog::open(dialog::OpenDialogOptions::default()).await?;
// 文件系统(需要权限)
let contents = fs::read_text_file("path/to/file").await?;Troubleshooting
故障排除
WASM not loading
WASM无法加载
- Verify in tauri.conf.json
withGlobalTauri: true - Check browser console for WASM errors
- Ensure target is installed
wasm32-unknown-unknown
- 验证tauri.conf.json中是否启用
withGlobalTauri: true - 检查浏览器控制台的WASM错误信息
- 确保已安装目标
wasm32-unknown-unknown
Hot-reload not working on mobile
移动端热重载不生效
- Set in Trunk.toml
ws_protocol = "ws" - Use for mobile access
address = "0.0.0.0" - Verify firewall allows connections on dev port
- 在Trunk.toml中设置
ws_protocol = "ws" - 使用以支持移动端访问
address = "0.0.0.0" - 验证防火墙允许开发端口的连接
Tauri APIs undefined
Tauri API未定义
- must be
withGlobalTauritrue - Check exists in browser console
window.__TAURI__ - Verify tauri-wasm version matches Tauri version
- 必须启用
withGlobalTauri - 在浏览器控制台检查是否存在
window.__TAURI__ - 确保tauri-wasm版本与Tauri版本匹配
Large WASM binary size
WASM二进制体积过大
- Enable release profile optimizations
- Use for size optimization
opt-level = "z" - Enable LTO with
lto = true - Consider post-processing
wasm-opt
- 启用Release配置的优化选项
- 使用进行体积优化
opt-level = "z" - 启用LTO()
lto = true - 考虑使用进行后处理
wasm-opt
Trunk build fails
Trunk构建失败
- Check Cargo.toml has
crate-type = ["cdylib", "rlib"] - Verify index.html has correct directives
data-trunk - Ensure no server-side features enabled in framework
- 检查Cargo.toml是否包含
crate-type = ["cdylib", "rlib"] - 验证index.html是否有正确的指令
data-trunk - 确保框架未启用服务器端特性
Version Compatibility
版本兼容性
| Component | Version |
|---|---|
| Tauri | 2.x |
| Trunk | 0.17+ |
| Leptos | 0.6+ |
| wasm-bindgen | 0.2.x |
| tauri-wasm | 2.x |
Always match version with your Tauri version.
tauri-wasm| 组件 | 版本 |
|---|---|
| Tauri | 2.x |
| Trunk | 0.17+ |
| Leptos | 0.6+ |
| wasm-bindgen | 0.2.x |
| tauri-wasm | 2.x |
请始终保持版本与Tauri版本一致。
tauri-wasm