Rust服务器端渲染库dioxus-ssr的使用,dioxus-ssr实现高效Web组件SSR渲染

Rust服务器端渲染库dioxus-ssr的使用,dioxus-ssr实现高效Web组件SSR渲染

概述

Dioxus SSR提供将Dioxus组件渲染为有效HTML的工具。渲染完成后,HTML可以在客户端进行水合(hydration)或从您选择的Web服务器提供服务。

# use dioxus::prelude::*;
fn app() -> Element {
  rsx!{
    div {"hello world!"}
  }
}

let mut vdom = VirtualDom::new(app);
vdom.rebuild_in_place();

let text = dioxus_ssr::render(&vdom);
assert_eq!(text, "<div>hello world!</div>")

基本用法

最简单的例子是将一些rsx!节点渲染为HTML。这可以使用render_element API完成。

# use dioxus::prelude::*;
let content = dioxus_ssr::render_element(rsx!{
    div {
        for i in 0..5 {
            "Number: {i}"
        }
    }
});

渲染VirtualDom

# use dioxus::prelude::*;
# fn app() -> Element { todo!() }
let mut vdom = VirtualDom::new(app);
vdom.rebuild_in_place();

let content = dioxus_ssr::render(&vdom);

预渲染使用

这个库特别适用于在服务器端预生成页面,然后选择性加载Dioxus客户端以处理响应式元素。

要启用预渲染,只需将预渲染标志设置为true。

# use dioxus::prelude::*;
# fn App() -> Element { todo!() }
let mut vdom = VirtualDom::new(App);

vdom.rebuild_in_place();

let mut renderer = dioxus_ssr::Renderer::new();
renderer.pre_render = true;

let text = renderer.render(&vdom);

服务器端渲染使用

Dioxus SSR也可用于在服务器上渲染。您可以只将VirtualDOM渲染为字符串并将其发送给客户端。

# use dioxus::prelude::*;
fn App() -> Element {
  rsx! { div { "hello world!" } }
}
let mut vdom = VirtualDom::new(App);
vdom.rebuild_in_place();
let text = dioxus_ssr::render(&vdom);
assert_eq!(text, "<div>hello world!</div>")

完整示例

以下是一个完整的Dioxus SSR使用示例,展示了服务器端渲染和客户端水合的过程:

use dioxus::prelude::*;
use dioxus_ssr::Renderer;

// 定义组件
fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            h1 {"Dioxus SSR示例"}
            p {"这是一个服务器渲染的组件"}
            ul {
                for i in 0..5 {
                    li { "项目 {i}" }
                }
            }
        }
    })
}

// 服务器端渲染
fn render_server() -> String {
    let mut vdom = VirtualDom::new(App);
    vdom.rebuild_in_place();
    
    let mut renderer = Renderer::new();
    renderer.pre_render = true; // 启用预渲染
    
    renderer.render(&vdom)
}

// 客户端水合
#[cfg(target_arch = "wasm32")]
fn hydrate_client() {
    dioxus_web::launch_with_props(App, (), |c| c.hydrate(true));
}

fn main() {
    // 在服务器上
    let html = render_server();
    println!("Rendered HTML: {}", html);
    
    // 在客户端上
    #[cfg(target_arch = "wasm32")]
    hydrate_client();
}

这个示例展示了如何:

  1. 定义一个Dioxus组件
  2. 在服务器端渲染组件为HTML字符串
  3. 在客户端进行水合(hydration)以添加交互性

要运行这个示例,您需要在Cargo.toml中添加以下依赖:

[dependencies]
dioxus = "0.6"
dioxus-ssr = "0.6"
dioxus-web = { version = "0.6", optional = true }

Dioxus SSR提供了一种高效的方式来实现Web组件的服务器端渲染,同时保持客户端交互能力,是现代Web开发的强大工具。


1 回复

Rust服务器端渲染库dioxus-ssr的使用指南

简介

dioxus-ssr 是 Dioxus 框架的服务器端渲染(SSR)组件,它允许你在服务器上渲染 Dioxus 组件并将其作为 HTML 字符串发送到客户端。这种方式提供了更好的首屏加载性能和 SEO 支持。

主要特性

  • 高效的服务器端渲染
  • 与 Dioxus 框架无缝集成
  • 支持静态和动态渲染
  • 轻量级且高性能

安装

首先,确保你的 Cargo.toml 中包含以下依赖:

[dependencies]
dioxus = { version = "0.4", features = ["ssr"] }
dioxus-ssr = "0.4"

基本使用方法

1. 渲染简单组件

use dioxus::prelude::*;
use dioxus_ssr::render;

fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            h1 { "Hello, Dioxus SSR!" }
            p { "This is server-side rendered content." }
        }
    })
}

fn main() {
    let html = render(App);
    println!("{}", html);
}

2. 带属性的组件渲染

use dioxus::prelude::*;
use dioxus_ssr::render;

fn Greeting(cx: Scope, name: String) -> Element {
    cx.render(rsx! {
        h1 { "Hello, {name}!" }
    })
}

fn main() {
    let props = String::from("World");
    let html = render_with_props(Greeting, props);
    println!("{}", html);
}

3. 与Web框架集成示例(使用Axum)

use axum::{response::Html, routing::get, Router};
use dioxus::prelude::*;
use dioxus_ssr::render;

fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            h1 { "Welcome to Dioxus SSR with Axum" }
            p { "This content is rendered on the server." }
        }
    })
}

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(handler));

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn handler() -> Html<String> {
    Html(render(App))
}

高级用法

1. 预渲染静态页面

use dioxus::prelude::*;
use dioxus_ssr::render_static;

fn StaticPage(cx: Scope) -> Element {
    cx.render(rsx! {
        html {
            head {
                title { "Static Page" }
            }
            body {
                h1 { "This is a statically rendered page" }
                p { "Great for SEO and performance!" }
            }
        }
    })
}

fn main() {
    let html = render_static(StaticPage);
    std::fs::write("static_page.html", html).unwrap();
}

2. 结合客户端水合(Hydration)

// 服务器端代码
use dioxus::prelude::*;
use dioxus_ssr::render;

fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            h1 { "SSR with Hydration" }
            p { "This will be hydrated on the client." }
        }
    })
}

// 客户端代码 (通常在不同的文件中)
use dioxus::prelude::*;
use dioxus_web::Config;

fn main() {
    dioxus_web::launch_with_props(App, (), Config::default().hydrate(true));
}

3. 使用动态数据

use dioxus::prelude::*;
use dioxus_ssr::render_with_props;

#[derive(Props)]
struct PostProps<'a> {
    title: &'a str,
    content: &'a str,
}

fn Post<'a>(cx: Scope<'a, PostProps<'a>>) -> Element {
    cx.render(rsx! {
        article {
            h2 { "{cx.props.title}" }
            div { dangerous_inner_html: "{cx.props.content}" }
        }
    })
}

fn main() {
    let props = PostProps {
        title: "Rust is Awesome",
        content: "<p>Rust provides memory safety without garbage collection.</p>",
    };
    
    let html = render_with_props(Post, props);
    println!("{}", html);
}

性能优化技巧

  1. 缓存渲染结果:对于不经常变化的内容,可以缓存渲染结果
  2. 部分渲染:只渲染需要更新的部分组件
  3. 流式渲染:对于大型页面,考虑流式渲染
use dioxus::prelude::*;
use dioxus_ssr::{render, render_lazy};

fn LargeComponent(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            // 大量内容...
        }
    })
}

fn main() {
    // 普通渲染
    let _ = render(LargeComponent);
    
    // 惰性渲染(更高效的内存使用)
    let _ = render_lazy(LargeComponent);
}

注意事项

  1. 服务器端渲染的组件不能使用浏览器特定的API
  2. 确保在客户端和服务器端使用相同的组件结构
  3. 对于交互性强的组件,仍然需要客户端JavaScript

dioxus-ssr 是一个强大的工具,可以显著提升你的Web应用性能,特别是在需要良好SEO和快速首屏渲染的场景下。

完整示例DEMO

下面是一个完整的Axum集成示例,包含服务器端渲染和客户端水合:

// Cargo.toml
/*
[dependencies]
axum = "0.6"
dioxus = { version = "0.4", features = ["ssr"] }
dioxus-ssr = "0.4"
dioxus-web = "0.4"
tokio = { version = "1.0", features = ["full"] }
*/

// 服务器端 main.rs
use axum::{response::Html, routing::get, Router};
use dioxus::prelude::*;
use dioxus_ssr::render;

fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            h1 { "Dioxus SSR Full Example" }
            p { "This is server-rendered content" }
            div { id: "hydration-target",
                "This will be hydrated on the client"
            }
        }
    })
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(handler))
        .route("/client.js", get(client_handler));

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

async fn handler() -> Html<String> {
    let content = render(App);
    let html = format!(r#"
        <!DOCTYPE html>
        <html>
        <head>
            <title>Dioxus SSR Demo</title>
            <script src="/client.js"></script>
        </head>
        <body>
            {content}
        </body>
        </html>
    "#);
    Html(html)
}

async fn client_handler() -> &'static [u8] {
    // 这里应该是编译后的客户端JS文件内容
    // 实际项目中应该从文件系统读取
    include_bytes!("../client/dist/client.js")
}
// 客户端 lib.rs
use dioxus::prelude::*;
use dioxus_web::Config;

fn main() {
    dioxus_web::launch_with_props(App, (), Config::default().hydrate(true));
}

fn App(cx: Scope) -> Element {
    cx.render(rsx! {
        div {
            // 确保与服务器端结构一致
            h1 { "Dioxus SSR Full Example" }
            p { "This is server-rendered content" }
            div { id: "hydration-target",
                "Now hydrated on the client!"
            }
        }
    })
}
回到顶部