Server-Side Rendering
For lower-level control over the rendering process, you can use the dioxus-ssr
crate directly. This can be useful when integrating with a web framework that dioxus-fullstack
does not support, or pre-rendering pages.
Setup
For this guide, we're going to show how to use Dioxus SSR 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 ssr renderer as dependencies:
cargo add dioxus cargo add dioxus-ssr
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-ssr = { version = "*" } tokio = { version = "1.15.0", features = ["full"] }
Now, set up your Axum app to respond on an endpoint.
use axum::{response::Html, routing::get, Router}; use dioxus::prelude::*; #[tokio::main] async fn main() { let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000)); println!("listening on http://{}", addr); axum::Server::bind(&addr) .serve( Router::new() .route("/", get(app_endpoint)) .into_make_service(), ) .await .unwrap(); }
And then add our endpoint. We can either render rsx!
directly:
async fn app_endpoint() -> Html<String> { // render the rsx! macro to HTML Html(dioxus_ssr::render_lazy(rsx! { div { "hello world!" } })) }
Or we can render VirtualDoms.
async fn app_endpoint() -> Html<String> { // create a component that renders a div with the text "hello world" fn app(cx: Scope) -> Element { cx.render(rsx!(div { "hello world" })) } // create a VirtualDom with the app component let mut app = VirtualDom::new(app); // rebuild the VirtualDom before rendering let _ = app.rebuild(); // render the VirtualDom to HTML Html(dioxus_ssr::render_vdom(&app)) }
Multithreaded Support
The Dioxus VirtualDom, sadly, is not currently Send
. Internally, we use quite a bit of interior mutability which is not thread-safe.Send
, it is possible to render a VirtualDom immediately to a String – but you cannot hold the VirtualDom across an await point. For retained-state SSR (essentially LiveView), you'll need to spawn a VirtualDom on its own thread and communicate with it via channels or create a pool of VirtualDoms.must remain on the thread it started. We are working on loosening this requirement.