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();
}
这个示例展示了如何:
- 定义一个Dioxus组件
- 在服务器端渲染组件为HTML字符串
- 在客户端进行水合(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);
}
性能优化技巧
- 缓存渲染结果:对于不经常变化的内容,可以缓存渲染结果
- 部分渲染:只渲染需要更新的部分组件
- 流式渲染:对于大型页面,考虑流式渲染
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);
}
注意事项
- 服务器端渲染的组件不能使用浏览器特定的API
- 确保在客户端和服务器端使用相同的组件结构
- 对于交互性强的组件,仍然需要客户端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!"
}
}
})
}