The Bridge: Calling Rust from JavaScript
The Bridge: Calling Rust from JavaScript
Section titled “The Bridge: Calling Rust from JavaScript”The true power of Tauri comes from combining the easy UI development of the web with the raw performance of Rust. To do this, we use IPC (Inter-Process Communication). In Tauri, we call this the Command system.
Step 1: Creating a Rust Command
Section titled “Step 1: Creating a Rust Command”A command is simply a Rust function annotated with the #[tauri::command] macro. This macro handles the serialization of data automatically.
// src-tauri/src/lib.rs or main.rs
#[tauri::command]fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name)}Step 2: Registering the Command
Section titled “Step 2: Registering the Command”Defining the function isn’t enough; you must tell Tauri about it. We register commands inside the tauri::Builder invoke handler, usually found in your lib.rs (for v2 mobile compatibility structure) or main.rs.
#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() { tauri::Builder::default() // Register the command here .invoke_handler(tauri::generate_handler![greet]) .run(tauri::generate_context!()) .expect("error while running tauri application");}Step 3: Invoking from the Frontend
Section titled “Step 3: Invoking from the Frontend”On the JavaScript side, we use the invoke function provided by the @tauri-apps/api package. This function returns a Promise, making it easy to handle asynchronous data flow.
First, ensure you have the API installed (if not using the default template):
npm install @tauri-apps/apiThen, call the command:
import { invoke } from '@tauri-apps/api/core';
async function callGreet() { // The first argument is the command name (fn name in Rust) // The second argument is an object matching the Rust arguments const message = await invoke('greet', { name: 'World' }); console.log(message); // Prints: Hello, World! You've been greeted from Rust!}Handling Async Operations
Section titled “Handling Async Operations”Rust commands are asynchronous by nature when called from the frontend. This is excellent for heavy computations (like image processing or database queries) because it ensures your UI never freezes while waiting for the backend.
You can define your Rust function as async fn as well, and Tauri will handle the await logic seamlessly across the bridge.
#[tauri::command]async fn perform_heavy_task() -> String { // Simulate work std::thread::sleep(std::time::Duration::from_secs(2)); "Task Complete".to_string()}