Liveview

Liveview allows apps to run on the server and render in the browser. It uses WebSockets to communicate between the server and the browser.

Examples:

Support

Liveview is currently limited in capability when compared to the Web platform. Liveview apps run on the server in a native thread. This means that browser APIs are not available, so rendering WebGL, Canvas, etc is not as easy as the Web. However, native system APIs are accessible, so streaming, WebSockets, filesystem, etc are all viable APIs.

Setup

For this guide, we're going to show how to use Dioxus Liveview with Axum.

Make sure you have Rust and Cargo installed, and then create a new project:

cargo new --bin demo
cd demo

Add Dioxus and the liveview renderer with the Axum feature as dependencies:

cargo add dioxus
cargo add dioxus-liveview --features axum

Next, add all the Axum dependencies. This will be different if you're using a different Web Framework

cargo add tokio --features full
cargo add axum

Your dependencies should look roughly like this:

[dependencies]
axum = "0.4.5"
dioxus = { version = "*" }
dioxus-liveview = { version = "*", features = ["axum"] }
tokio = { version = "1.15.0", features = ["full"] }

Now, set up your Axum app to respond on an endpoint.

use axum::{extract::ws::WebSocketUpgrade, response::Html, routing::get, Router};
use dioxus::prelude::*;

#[tokio::main]
async fn main() {
    let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into();

    let view = dioxus_liveview::LiveViewPool::new();

    let app = Router::new()
        // The root route contains the glue code to connect to the WebSocket
        .route(
            "/",
            get(move || async move {
                Html(format!(
                    r#"
                <!DOCTYPE html>
                <html>
                <head> <title>Dioxus LiveView with Axum</title>  </head>
                <body> <div id="main"></div> </body>
                {glue}
                </html>
                "#,
                    // Create the glue code to connect to the WebSocket on the "/ws" route
                    glue = dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws"))
                ))
            }),
        )
        // The WebSocket route is what Dioxus uses to communicate with the browser
        .route(
            "/ws",
            get(move |ws: WebSocketUpgrade| async move {
                ws.on_upgrade(move |socket| async move {
                    // When the WebSocket is upgraded, launch the LiveView with the app component
                    _ = view.launch(dioxus_liveview::axum_socket(socket), app).await;
                })
            }),
        );

    println!("Listening on http://{addr}");

    axum::Server::bind(&addr.to_string().parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

And then add our app component:

fn app(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            "Hello, world!"
        }
    })
}

And that's it!

Hot Reload

  1. Hot reloading allows much faster iteration times inside of rsx calls by interpreting them and streaming the edits.
  2. It is useful when changing the styling/layout of a program, but will not help with changing the logic of a program.

Setup

Install dioxus-cli.

Usage

  1. Run:
dx serve --hot-reload --platform desktop
  1. Change some code within a rsx or render macro
  2. Save and watch the style change without recompiling

Limitations

  1. The interpreter can only use expressions that existed on the last full recompile. If you introduce a new variable or expression to the rsx call, it will require a full recompile to capture the expression.
  2. Components, Iterators, and some attributes can contain arbitrary rust code and will trigger a full recompile when changed.