Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tutorial 18: Wasm Island foundation

Rullst can generate a dual-target Island function: native builds emit a host element with serialized props, while wasm32-unknown-unknown builds export a hydration function.

Generate the component

cargo rullst make:island InteractiveChart

The generated src/islands/interactive_chart.rs uses the supported macro:

#![allow(unused)]
fn main() {
use rullst::island;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::{closure::Closure, JsCast};

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct InteractiveChartProps {
    pub initial_value: i32,
}

#[island]
pub fn interactive_chart(props: InteractiveChartProps) {
    #[cfg(not(target_arch = "wasm32"))]
    {
        format!(
            "<button type=\"button\" data-counter=\"{}\">Count: {}</button>",
            props.initial_value, props.initial_value
        )
    }

    #[cfg(target_arch = "wasm32")]
    {
        let mut value = props.initial_value;
        element.set_text_content(Some(&format!("Count: {value}")));

        let button = element.clone();
        let closure = Closure::<dyn FnMut()>::new(move || {
            value = value.saturating_add(1);
            button.set_text_content(Some(&format!("Count: {value}")));
        });

        if element
            .add_event_listener_with_callback("click", closure.as_ref().unchecked_ref())
            .is_ok()
        {
            closure.forget();
        }

        String::new()
    }
}
}

The element binding in the Wasm block is supplied by #[island]. The command also declares the module in src/islands/mod.rs, adds pub mod islands; to src/lib.rs (creating that file when it is absent), and adds any missing serde, serde_json, wasm-bindgen and web-sys dependencies.

On the server the island function returns rullst::html::Markup: the component’s HTML wrapped in its data-island element. Place it in a page by interpolating the call inside html!, as {interactive_chart(props)}; it is inserted as HTML, not escaped. The module belongs to the library target (src/lib.rs), so the starters’ src/main.rs imports it through the package name, with - written as _: use <package_name>::islands::interactive_chart::{interactive_chart, InteractiveChartProps};.

Build and load the artifact

cargo rullst build:client

The command parses Cargo.toml, adds cdylib to the [lib] crate-type array when needed (writing ["cdylib", "rlib"] when the key is absent), installs/checks the Wasm target and wasm-bindgen-cli, builds the library, locates the artifact using lib.name or package.name, writes bindings under static/, and generates the static/rullst-islands.js hydration orchestrator. Review these manifest, network, and toolchain side effects in CI and pin the required tools for reproducible releases. Load the orchestrator from the page with <script type="module" src="/static/rullst-islands.js"></script>, as the command output shows.

This is a useful foundation, not a complete frontend framework: routing, application state, accessibility, CSP-compatible asset delivery, cache busting, error reporting and browser E2E remain application/release work.