Crate tauri_specta

Source
Expand description

Tauri Specta will generate a Typescript or JSDoc file (powered by Specta) to provide a typesafe interface to your Tauri backend.

§Installation

Tauri Specta v2 is still in beta, and requires using Tauri v2 and Specta v2 lands as stable.

It is really important you use = in your versions to ensure your project will not break after future updates!

To get started run the following commands to add the required dependencies to your Cargo.toml:

# Always required
cargo add tauri@2.0 specta@=2.0.0-rc.21

# Typescript
cargo add specta-typescript@0.0.9
cargo add tauri-specta@=2.0.0-rc.21 --features derive,typescript

# JSDoc
cargo add specta-jsdoc@0.0.9
cargo add tauri-specta@=2.0.0-rc.21 --features derive,javascript

§Features

There are the following optional features which can be enabled:

  • derive - Enables the Event derive macro. This is only required if your using events.
  • javascript - Enables the JSDoc exporter.
  • typescript - Enables the Typescript exporter.

§Setup

The follow is a minimal example of how to setup Tauri Specta with Typescript.

#![cfg_attr(
    all(not(debug_assertions), target_os = "windows"),
    windows_subsystem = "windows"
)]

use serde::{Deserialize, Serialize};
use specta_typescript::Typescript;
use tauri_specta::{collect_commands, Builder};

#[tauri::command]
#[specta::specta] // < You must annotate your commands
fn hello_world(my_name: String) -> String {
    format!("Hello, {my_name}! You've been greeted from Rust!")
}

fn main() {
    let mut builder = Builder::<tauri::Wry>::new()
        // Then register them (separated by a comma)
        .commands(collect_commands![hello_world,]);

    #[cfg(debug_assertions)] // <- Only export on non-release builds
    builder
        .export(Typescript::default(), "../src/bindings.ts")
        .expect("Failed to export typescript bindings");

    tauri::Builder::default()
        // and finally tell Tauri how to invoke them
        .invoke_handler(builder.invoke_handler())
        .setup(move |app| {
            // This is also required if you want to use events
            builder.mount_events(app);

            Ok(())
        })
        // on an actual app, remove the string argument
        .run(tauri::generate_context!("tests/tauri.conf.json"))
        .expect("error while running tauri application");
}

§Export to JSDoc

If your interested in using JSDoc instead of Typescript you can replace the specta_typescript::Typescript struct with specta_jsdoc::JSDoc like the following:

let mut builder = tauri_specta::Builder::<tauri::Wry>::new();

#[cfg(debug_assertions)]
builder
    .export(specta_jsdoc::JSDoc::default(), "../src/bindings.js")
    .expect("Failed to export typescript bindings");

§Usage on frontend

import { commands, events } from "./bindings"; // This should point to the file we export from Rust

console.log(await commands.greet("Brendan"));

§Custom types

Similar to serde::Serialize you must put the specta::Type derive macro on your own types to allow Specta to understand your types. For example:

use serde::{Serialize, Deserialize};
use specta::Type;

#[derive(Serialize, Deserialize, Type)]
pub struct MyStruct {
    a: String
}

// Call `typ()` as much as you want.
let mut builder = tauri_specta::Builder::<tauri::Wry>::new().typ::<MyStruct>();

§Events

You can also make events typesafe by following the following example:

use serde::{Serialize, Deserialize};
use specta::Type;
use tauri_specta::{Builder, collect_commands, collect_events, Event};

// Add `tauri_specta::Event` to your event
#[derive(Serialize, Deserialize, Debug, Clone, Type, Event)]
pub struct DemoEvent(String);

let mut builder = Builder::<tauri::Wry>::new()
        // and then register it to your builder
        .events(collect_events![DemoEvent]);

tauri::Builder::default()
        .invoke_handler(builder.invoke_handler())
        .setup(move |app| {
            // Ensure you mount your events!
            builder.mount_events(app);

            // Now you can use them

            DemoEvent::listen(app, |event| {
                println!("{:?}", event.payload);
            });

            DemoEvent("Test".into()).emit(app).unwrap();

            Ok(())
        });

and it can be used on the frontend like the following:

import { commands, events } from "./bindings";
import { appWindow } from "@tauri-apps/api/window";

// For all windows
events.demoEvent.listen((e) => console.log(e));

// For a single window
events.demoEvent(appWindow).listen((e) => console.log(e));

// Emit to the backend and all windows
await events.demoEvent.emit("Test")

// Emit to a window
await events.demoEvent(appWindow).emit("Test")

Refer to Event for all the possible methods for listening and emitting events.

§Channel

Coming soon…

Macros§

Structs§

  • Builder for configuring Tauri Specta in your application.
  • A wrapper around the output of the collect_commands macro.
  • A wrapper around the output of the collect_commands macro.
  • The context of what needs to be exported. Used when implementing LanguageExt.
  • A typed event that was emitted.

Enums§

Traits§

  • Extends your event type with typesafe methods for listening to and emitting events.
  • Implemented for all languages which Tauri Specta supports exporting to.

Derive Macros§

  • Eventderive
    Implements the Event trait for a struct.