Rust Web框架Leptos与Spin集成宏库leptos-spin-macro的使用,实现高效无服务器函数开发
Rust Web框架Leptos与Spin集成宏库leptos-spin-macro的使用,实现高效无服务器函数开发
安装
在项目目录中运行以下Cargo命令:
cargo add leptos-spin-macro
或者在Cargo.toml中添加以下行:
leptos-spin-macro = "0.2.0"
使用示例
leptos-spin-macro提供了宏来简化Leptos与Spin无服务器框架的集成。下面是一个完整的使用示例:
use leptos::*;
use leptos_spin_macro::server;
// 使用#[server]宏标记无服务器函数
#[server(MyServerFunction, "/api")]
pub async fn my_server_function(input: String) -> Result<String, ServerFnError> {
// 在这里编写服务器端逻辑
Ok(format!("Processed: {}", input))
}
// 在Leptos组件中使用
#[component]
pub fn MyComponent() -> impl IntoView {
let action = create_server_action::<MyServerFunction>();
view! {
<div>
<form on:submit=|ev| {ev.prevent_default(); action.dispatch(MyServerFunction {input: "Hello".to_string()})}>
<button type="submit">Submit</button>
</form>
{move || {
action.value().get().map(|result| match result {
Ok(response) => view! { <p>{response}</p> },
Err(e) => view! { <p>Error: {e.to_string()}</p> },
})
}}
</div>
}
}
完整示例Demo
下面是一个完整的Spin无服务器应用示例,展示了如何使用leptos-spin-macro:
// src/lib.rs
use leptos::*;
use leptos_spin_macro::server;
#[server(AddNumbers, "/api/add")]
pub async fn add_numbers(a: i32, b: i32) -> Result<i32, ServerFnError> {
Ok(a + b)
}
#[component]
pub fn Calculator() -> impl IntoView {
let add_action = create_server_action::<AddNumbers>();
let result = add_action.value();
view! {
<div>
<h1>Calculator</h1>
<form on:submit=|ev| {
ev.prevent_default();
add_action.dispatch(AddNumbers { a: 5, b: 7 });
}>
<button type="submit">Add 5 + 7</button>
</form>
<p>
{move || match result.get() {
Some(Ok(sum)) => format!("Result: {}", sum),
Some(Err(e)) => format!("Error: {}", e),
None => "Waiting...".to_string(),
}}
</p>
</div>
}
}
#[spin_sdk::http_component]
fn handle_request(req: http::Request<()>) -> Result<http::Response<()>> {
let mut conf = leptos::get_configuration(None)?;
conf.leptos_options.output_name = "calculator".to_string();
leptos_spin::handle_http(req, conf, || view! { <Calculator/> })
}
配置
在spin.toml中配置应用:
spin_version = "1"
trigger = { type = "http", base = "/" }
[[component]]
id = "calculator"
source = "target/wasm32-wasi/release/calculator.wasm"
allowed_outbound_hosts = []
[component.trigger]
route = "/..."
构建与运行
# 构建Wasm组件
cargo build --target wasm32-wasi --release
# 运行Spin应用
spin up
这个示例展示了如何:
- 定义无服务器函数
- 在Leptos组件中使用
- 配置Spin应用
- 构建和运行无服务器应用
leptos-spin-macro简化了Leptos和Spin的集成,使开发者能够专注于业务逻辑而不是框架集成细节。
1 回复
Rust Web框架Leptos与Spin集成宏库leptos-spin-macro的使用
概述
leptos-spin-macro
是一个将Leptos前端框架与Spin无服务器框架集成的Rust宏库,它简化了在Spin环境中使用Leptos构建高效无服务器函数的过程。
主要特性
- 无缝集成Leptos和Spin框架
- 简化无服务器函数的创建流程
- 提供高效的响应式前端开发体验
- 支持服务器端渲染(SSR)
使用方法
1. 添加依赖
首先在Cargo.toml
中添加必要的依赖:
[dependencies]
leptos = "0.5"
leptos-spin-macro = "0.1"
spin-sdk = "2.0"
2. 基本使用示例
use leptos::*;
use leptos_spin_macro::component;
#[component]
pub fn HelloWorld() -> impl IntoView {
view! {
<h1>"Hello, Spin + Leptos!"</h1>
}
}
#[spin_component]
fn handle_request() -> impl IntoView {
view! {
<html>
<head>
<title>"Leptos Spin App"</title>
</head>
<body>
<HelloWorld/>
</body>
</html>
}
}
3. 处理请求数据
use spin_sdk::http::{Request, Response};
use leptos_spin_macro::{spin_component, server};
#[server]
async fn get_data() -> Result<String, ServerFnError> {
// 这里可以执行异步操作,如数据库查询等
Ok("Data from server".to_string())
}
#[spin_component]
fn handle_request(req: Request) -> impl IntoView {
let data = create_resource(|| (), |_| async { get_data().await });
view! {
<div>
<h1>"Data Fetching Example"</h1>
<Suspense fallback=|| view! { <p>"Loading..."</p> }>
{move || data.read().map(|data|
match data {
Ok(data) => view! { <p>{data}</p> },
Err(e) => view! { <p>"Error loading data"</p> }
}
)}
</Suspense>
</div>
}
}
4. 路由处理
use leptos::*;
use leptos_router::*;
use leptos_spin_macro::spin_component;
#[spin_component]
fn handle_request(req: Request) -> impl IntoView {
view! {
<Router>
<Routes>
<Route path="/" view=HomePage/>
<Route path="/about" view=AboutPage/>
</Routes>
</Router>
}
}
#[component]
fn HomePage() -> impl IntoView {
view! { <h1>"Welcome to the Home Page"</h1> }
}
#[component]
fn AboutPage() -> impl IntoView {
view! { <h1>"About Us"</h1> }
}
高级用法
1. 自定义响应头
use spin_sdk::http::{Request, Response};
use leptos_spin_macro::spin_component;
#[spin_component]
fn handle_request(req: Request) -> impl IntoView {
let headers = vec![
("Content-Type".to_string(), "text/html".to_string()),
("Custom-Header".to_string(), "Value".to_string())
];
view! {
headers=headers,
<h1>"Custom Headers Example"</h1>
}
}
2. 状态管理
use leptos::*;
use leptos_spin_macro::spin_component;
#[spin_component]
fn handle_request(req: Request) -> impl IntoView {
let (count, set_count) = create_signal(0);
view! {
<div>
<button on:click=move |_| set_count.update(|n| *n += 1)>
"Click me: " {count}
</button>
</div>
}
}
部署到Spin
- 构建WASM组件:
cargo build --target wasm32-wasi --release
- 创建
spin.toml
配置文件:
spin_version = "1"
name = "leptos-spin-app"
trigger = { type = "http", base = "/" }
version = "0.1.0"
[[component]]
source = "target/wasm32-wasi/release/your_app.wasm"
id = "leptos-app"
[component.trigger]
route = "/..."
- 运行应用:
spin up
注意事项
- 确保使用Rust nightly工具链,因为Leptos需要一些nightly特性
- WASM目标需要正确安装:
rustup target add wasm32-wasi
- 对于生产部署,考虑添加适当的错误处理和日志记录
这个集成库为开发者提供了在Spin无服务器环境中使用Leptos框架的便捷方式,结合了两者的优势,使得构建高效、响应式的无服务器应用变得更加简单。
完整示例demo
以下是一个结合了路由、数据获取和状态管理的完整示例:
use leptos::*;
use leptos_router::*;
use leptos_spin_macro::{spin_component, server};
use spin_sdk::http::{Request, Response};
// 定义服务器端函数
#[server]
async fn fetch_user_data(id: u32) -> Result<String, ServerFnError> {
// 模拟异步获取数据
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
Ok(format!("User data for ID: {}", id))
}
// 主页组件
#[component]
fn HomePage() -> impl IntoView {
let (count, set_count) = create_signal(0);
view! {
<div>
<h1>"Welcome to Leptos Spin App"</h1>
<button on:click=move |_| set_count.update(|n| *n += 1)>
"Clicked: " {count} " times"
</button>
<p>
<a href="/about">"Go to About Page"</a>
</p>
<p>
<a href="/user/42">"View User 42"</a>
</p>
</div>
}
}
// 关于页面组件
#[component]
fn AboutPage() -> impl IntoView {
view! {
<div>
<h1>"About This App"</h1>
<p>"This is a demo app combining Leptos and Spin"</p>
<p>
<a href="/">"Back to Home"</a>
</p>
</div>
}
}
// 用户详情页面组件
#[component]
fn UserPage(id: u32) -> impl IntoView {
let user_data = create_resource(move || id, |id| async move {
fetch_user_data(id).await
});
view! {
<div>
<h1>"User Profile"</h1>
<p>"User ID: " {id}</p>
<Suspense fallback=|| view! { <p>"Loading user data..."</p> }>
{move || user_data.read().map(|data|
match data {
Ok(data) => view! { <p>{data}</p> },
Err(_) => view! { <p>"Error loading data"</p> }
}
)}
</Suspense>
<p>
<a href="/">"Back to Home"</a>
</p>
</div>
}
}
// 主处理函数
#[spin_component]
fn handle_request(req: Request) -> impl IntoView {
// 设置自定义响应头
let headers = vec![
("Content-Type".to_string(), "text/html".to_string()),
("X-Framework".to_string(), "Leptos+Spin".to_string())
];
view! {
headers=headers,
<html>
<head>
<title>"Leptos Spin Demo"</title>
</head>
<body>
<Router>
<Routes>
<Route path="/" view=HomePage/>
<Route path="/about" view=AboutPage/>
<Route path="/user/:id" view=|id: u32| view! {
<UserPage id=id/>
}/>
</Routes>
</Router>
</body>
</html>
}
}
这个完整示例展示了:
- 基本的路由配置
- 服务器端数据获取
- 客户端状态管理
- 自定义响应头设置
- 异步数据加载与Suspense处理
- 参数化路由
要运行这个示例,请按照前面提到的部署步骤进行操作。