integrating-tauri-rust-frontends

安装量: 64
排名: #11696

安装

npx skills add https://github.com/dchuk/claude-code-tauri-skills --skill integrating-tauri-rust-frontends

Tauri Rust/WASM Frontend Integration

This skill covers integrating Rust-based frontend frameworks with Tauri v2 for building desktop and mobile applications with 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.

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 window.TAURI and wasm-bindgen. WebSocket Protocol - Configure ws_protocol = "ws" for hot-reload on mobile development. 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)

Configuration Files Tauri Configuration (src-tauri/tauri.conf.json) { "build": { "beforeDevCommand": "trunk serve", "devUrl": "http://localhost:1420", "beforeBuildCommand": "trunk build", "frontendDist": "../dist" }, "app": { "withGlobalTauri": true } }

Key settings:

beforeDevCommand: Runs Trunk dev server before Tauri devUrl: URL where Trunk serves the frontend (default: 1420 for Leptos, 8080 for plain Trunk) beforeBuildCommand: Builds WASM bundle before packaging frontendDist: Path to built frontend assets withGlobalTauri: Required for WASM - Exposes window.TAURI for API access Trunk Configuration (Trunk.toml) [ build ] target = "./index.html" dist = "./dist"

[ watch ] ignore = ["./src-tauri"]

[ serve ] port = 1420 open = false

[ serve.ws ] ws_protocol = "ws"

Key settings:

target: HTML entry point with Trunk directives ignore: Prevents watching Tauri backend changes port: Must match devUrl in tauri.conf.json open = false: Prevents browser auto-open (Tauri handles display) ws_protocol = "ws": Required for mobile hot-reload Frontend Cargo.toml (Root) [ package ] name = "my-app-frontend" version = "0.1.0" edition = "2021"

[ lib ] crate-type = ["cdylib", "rlib"]

[ dependencies ]

Core WASM dependencies

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

tauri-wasm = { version = "2", features = ["all"] }

Choose your framework:

For Leptos:

leptos = { version = "0.6", features = ["csr"] }

For Yew:

yew =

For Dioxus:

dioxus =

[ 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 HTML Entry Point (index.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>
<link data-trunk rel="rust" href="." data-wasm-opt="z" /> </body> </html>

Trunk directives:

data-trunk rel="css": Include CSS files data-trunk rel="rust": Compile Rust crate to WASM data-wasm-opt="z": Optimize for size Leptos Setup Leptos-Specific Cargo.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 = true

Leptos Main Entry (src/main.rs) use leptos::*;

mod app; use app::App;

fn main() { console_error_panic_hook::set_once(); mount_to_body(|| view! { }); }

Leptos App Component (src/app.rs) 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 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

In src-tauri/src/main.rs:

[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

Install Trunk

cargo install trunk

Add WASM target

rustup target add wasm32-unknown-unknown

Development (runs Trunk + Tauri)

cd src-tauri && cargo tauri dev

Build for production

cd src-tauri && cargo tauri build

Trunk only (for frontend debugging)

trunk serve --port 1420

Build WASM only

trunk build --release

Mobile Development

For mobile platforms, additional configuration is needed:

Trunk.toml for Mobile [ 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-reload

tauri.conf.json for Mobile { "build": { "beforeDevCommand": "trunk serve --address 0.0.0.0", "devUrl": "http://YOUR_LOCAL_IP:1420" } }

Replace YOUR_LOCAL_IP with your machine's local IP (e.g., 192.168.1.100).

Accessing Tauri APIs from WASM Method 1: Direct wasm-bindgen (Recommended for control) 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;

// 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 { 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 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?;

Troubleshooting WASM not loading Verify withGlobalTauri: true in tauri.conf.json Check browser console for WASM errors Ensure wasm32-unknown-unknown target is installed Hot-reload not working on mobile Set ws_protocol = "ws" in Trunk.toml Use address = "0.0.0.0" for mobile access Verify firewall allows connections on dev port Tauri APIs undefined withGlobalTauri must be true Check window.TAURI exists in browser console Verify tauri-wasm version matches Tauri version Large WASM binary size Enable release profile optimizations Use opt-level = "z" for size optimization Enable LTO with lto = true Consider wasm-opt post-processing Trunk build fails Check Cargo.toml has crate-type = ["cdylib", "rlib"] Verify index.html has correct data-trunk directives Ensure no server-side features enabled in framework Version Compatibility Component Version Tauri 2.x Trunk 0.17+ Leptos 0.6+ wasm-bindgen 0.2.x tauri-wasm 2.x

Always match tauri-wasm version with your Tauri version.

返回排行榜