From 89b1e56fc3641214b6c011140076dc5b6a5eb5ab Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 18 Jan 2024 11:39:51 -0600 Subject: [PATCH] fix other fullstack adapters --- Cargo.lock | 5 - .../examples/axum-hello-world/src/main.rs | 7 +- .../examples/axum-router/src/main.rs | 3 +- .../examples/salvo-hello-world/src/main.rs | 3 +- .../examples/warp-hello-world/Cargo.toml | 13 +-- .../examples/warp-hello-world/src/main.rs | 24 +--- .../fullstack/src/adapters/salvo_adapter.rs | 30 +++-- .../fullstack/src/adapters/warp_adapter.rs | 107 +++++++++++------- packages/fullstack/src/config.rs | 8 +- 9 files changed, 105 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea347b119..abdba3772 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10966,16 +10966,11 @@ name = "warp-hello-world" version = "0.1.0" dependencies = [ "dioxus", - "dioxus-fullstack", - "dioxus-web", - "execute", "reqwest", "serde", - "simple_logger", "tracing", "tracing-subscriber", "tracing-wasm", - "warp", ] [[package]] diff --git a/packages/fullstack/examples/axum-hello-world/src/main.rs b/packages/fullstack/examples/axum-hello-world/src/main.rs index 33127af38..93f88beb7 100644 --- a/packages/fullstack/examples/axum-hello-world/src/main.rs +++ b/packages/fullstack/examples/axum-hello-world/src/main.rs @@ -1,8 +1,7 @@ //! Run with: //! //! ```sh -//! dx build --features web --release -//! cargo run --features ssr --release +//! dx serve --platform fullstack //! ``` #![allow(non_snake_case, unused)] @@ -10,14 +9,10 @@ use dioxus::prelude::*; use serde::{Deserialize, Serialize}; fn app() -> Element { - // let state = use_server_future(|| async move { get_server_data().await.unwrap() })?; - // let state = state.value(); - let mut count = use_signal(|| 0); let text = use_signal(|| "...".to_string()); rsx! { - // div { "Server state: {state}" } h1 { "High-Five counter: {count}" } button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } diff --git a/packages/fullstack/examples/axum-router/src/main.rs b/packages/fullstack/examples/axum-router/src/main.rs index efb0598e6..c6447355d 100644 --- a/packages/fullstack/examples/axum-router/src/main.rs +++ b/packages/fullstack/examples/axum-router/src/main.rs @@ -1,8 +1,7 @@ //! Run with: //! //! ```sh -//! dx build --features web --release -//! cargo run --features ssr --release +//! dx serve --platform fullstack //! ``` use dioxus::prelude::*; diff --git a/packages/fullstack/examples/salvo-hello-world/src/main.rs b/packages/fullstack/examples/salvo-hello-world/src/main.rs index 51186e442..fb6099129 100644 --- a/packages/fullstack/examples/salvo-hello-world/src/main.rs +++ b/packages/fullstack/examples/salvo-hello-world/src/main.rs @@ -1,8 +1,7 @@ //! Run with: //! //! ```sh -//! dx build --features web --release -//! cargo run --features ssr --release +//! dx serve --platform fullstack //! ``` #![allow(non_snake_case, unused)] diff --git a/packages/fullstack/examples/warp-hello-world/Cargo.toml b/packages/fullstack/examples/warp-hello-world/Cargo.toml index c2246a58d..cb14b7207 100644 --- a/packages/fullstack/examples/warp-hello-world/Cargo.toml +++ b/packages/fullstack/examples/warp-hello-world/Cargo.toml @@ -7,19 +7,14 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -dioxus-web = { workspace = true, features=["hydrate"], optional = true } -dioxus = { workspace = true } -dioxus-fullstack = { workspace = true } +dioxus = { workspace = true, features = ["fullstack"] } serde = "1.0.159" -warp = { version = "0.3.3", optional = true } -execute = "0.2.12" -reqwest = "0.11.18" -simple_logger = "4.2.0" tracing-wasm = "0.2.1" tracing.workspace = true tracing-subscriber = "0.3.17" +reqwest = "0.11.18" [features] default = [] -ssr = ["warp", "dioxus-fullstack/warp"] -web = ["dioxus-web"] +ssr = ["dioxus/warp"] +web = ["dioxus/web"] diff --git a/packages/fullstack/examples/warp-hello-world/src/main.rs b/packages/fullstack/examples/warp-hello-world/src/main.rs index 51186e442..9bd155c68 100644 --- a/packages/fullstack/examples/warp-hello-world/src/main.rs +++ b/packages/fullstack/examples/warp-hello-world/src/main.rs @@ -1,31 +1,17 @@ //! Run with: //! //! ```sh -//! dx build --features web --release -//! cargo run --features ssr --release +//! dx serve --platform fullstack //! ``` #![allow(non_snake_case, unused)] use dioxus::prelude::*; -use dioxus_fullstack::{launch, prelude::*}; -use serde::{Deserialize, Serialize}; - -#[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)] -struct AppProps { - count: i32, -} - -fn app(cx: Scope) -> Element { - let state = - use_server_future((), |()| async move { get_server_data().await.unwrap() })?.value(); +fn app() -> Element { let mut count = use_signal(|| 0); let text = use_signal(|| "...".to_string()); rsx! { - div { - "Server state: {state}" - } h1 { "High-Five counter: {count}" } button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } @@ -46,14 +32,14 @@ fn app(cx: Scope) -> Element { } } -#[server(PostServerData)] +#[server] async fn post_server_data(data: String) -> Result<(), ServerFnError> { println!("Server received: {}", data); Ok(()) } -#[server(GetServerData)] +#[server] async fn get_server_data() -> Result { Ok(reqwest::get("https://httpbin.org/ip").await?.text().await?) } @@ -64,5 +50,5 @@ fn main() { #[cfg(feature = "ssr")] tracing_subscriber::fmt::init(); - LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch() + launch(app); } diff --git a/packages/fullstack/src/adapters/salvo_adapter.rs b/packages/fullstack/src/adapters/salvo_adapter.rs index 0a3f9319f..39da4e4f1 100644 --- a/packages/fullstack/src/adapters/salvo_adapter.rs +++ b/packages/fullstack/src/adapters/salvo_adapter.rs @@ -49,6 +49,7 @@ //! } //! ``` +use dioxus_lib::prelude::*; use http_body_util::{BodyExt, Limited}; use hyper::body::Body as HyperBody; use hyper::StatusCode; @@ -201,10 +202,11 @@ pub trait DioxusRouterExt { /// /// fn app() -> Element {todo!()} /// ``` - fn serve_dioxus_application( + fn serve_dioxus_application( self, server_fn_path: &'static str, - cfg: impl Into>, + cfg: impl Into, + virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, ) -> Self; } @@ -281,10 +283,11 @@ impl DioxusRouterExt for Router { self } - fn serve_dioxus_application( + fn serve_dioxus_application( self, server_fn_path: &'static str, - cfg: impl Into>, + cfg: impl Into, + virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, ) -> Self { let cfg = cfg.into(); @@ -376,19 +379,26 @@ async fn convert_response(response: HyperResponse, res: &mut Response) { } /// A handler that renders a Dioxus application to HTML using server-side rendering. -pub struct SSRHandler { - cfg: ServeConfig

, +pub struct SSRHandler { + config: ServeConfig, + virtual_dom: Box VirtualDom + Send + Sync>, } -impl SSRHandler

{ +impl SSRHandler { /// Creates a new SSR handler with the given configuration. - pub fn new(cfg: ServeConfig

) -> Self { - Self { cfg } + pub fn new( + config: ServeConfig, + virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static, + ) -> Self { + Self { + config, + virtual_dom: Box::new(virtual_dom), + } } } #[async_trait] -impl Handler for SSRHandler

{ +impl Handler for SSRHandler { async fn handle( &self, req: &mut Request, diff --git a/packages/fullstack/src/adapters/warp_adapter.rs b/packages/fullstack/src/adapters/warp_adapter.rs index 92a038d15..de0fb3c31 100644 --- a/packages/fullstack/src/adapters/warp_adapter.rs +++ b/packages/fullstack/src/adapters/warp_adapter.rs @@ -52,6 +52,7 @@ use crate::{ }; use crate::server_fn_service; +use dioxus_lib::prelude::VirtualDom; use server_fn::{Encoding, Payload, ServerFunctionRegistry}; use std::error::Error; use std::sync::Arc; @@ -179,68 +180,85 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R /// todo!() /// } /// ``` -pub fn serve_dioxus_application( +pub fn serve_dioxus_application( server_fn_route: &'static str, - cfg: impl Into>, + cfg: impl Into, + virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, ) -> BoxedFilter<(impl Reply,)> { let cfg = cfg.into(); // Serve the dist folder and the index.html file let serve_dir = warp::fs::dir(cfg.assets_path); + let virtual_dom_factory = + Arc::new(virtual_dom_factory) as Arc VirtualDom + Send + Sync + 'static>; + connect_hot_reload() // First register the server functions .or(register_server_fns(server_fn_route)) // Then the index route - .or(path::end().and(render_ssr(cfg.clone()))) + .or(path::end().and(render_ssr(cfg.clone(), { + let virtual_dom_factory = virtual_dom_factory.clone(); + move || virtual_dom_factory() + }))) // Then the static assets .or(serve_dir) // Then all other routes - .or(render_ssr(cfg)) + .or(render_ssr(cfg, move || virtual_dom_factory())) .boxed() } /// Server render the application. -pub fn render_ssr( - cfg: ServeConfig

, +pub fn render_ssr( + cfg: ServeConfig, + virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, ) -> impl Filter + Clone { warp::get() .and(request_parts()) - .and(with_ssr_state(&cfg)) - .then(move |parts: http::request::Parts, renderer: SSRState| { - let route = parts.uri.path().to_string(); - let parts = Arc::new(RwLock::new(parts)); - let cfg = cfg.clone(); - async move { - let server_context = DioxusServerContext::new(parts); + .and(with_ssr_state(&cfg, virtual_dom_factory)) + .then( + move |parts: http::request::Parts, + (renderer, virtual_dom_factory): ( + SSRState, + Arc VirtualDom + Send + Sync + 'static>, + )| { + let route = parts.uri.path().to_string(); + let parts = Arc::new(RwLock::new(parts)); + let cfg = cfg.clone(); + async move { + let server_context = DioxusServerContext::new(parts); - match renderer.render(route, &cfg, &server_context).await { - Ok(rendered) => { - let crate::render::RenderResponse { html, freshness } = rendered; + match renderer + .render(route, &cfg, move || virtual_dom_factory(), &server_context) + .await + { + Ok(rendered) => { + let crate::render::RenderResponse { html, freshness } = rendered; - let mut res = Response::builder() - .header("Content-Type", "text/html") - .body(html) - .unwrap(); + let mut res = Response::builder() + .header("Content-Type", "text/html") + .body(html) + .unwrap(); - let headers_mut = res.headers_mut(); - let headers = server_context.response_parts().unwrap().headers.clone(); - for (key, value) in headers.iter() { - headers_mut.insert(key, value.clone()); + let headers_mut = res.headers_mut(); + let headers = server_context.response_parts().unwrap().headers.clone(); + for (key, value) in headers.iter() { + headers_mut.insert(key, value.clone()); + } + freshness.write(headers_mut); + + res + } + Err(err) => { + tracing::error!("Failed to render ssr: {}", err); + Response::builder() + .status(500) + .body("Failed to render ssr".into()) + .unwrap() } - freshness.write(headers_mut); - - res - } - Err(err) => { - tracing::error!("Failed to render ssr: {}", err); - Response::builder() - .status(500) - .body("Failed to render ssr".into()) - .unwrap() } } - } - }) + }, + ) } /// An extractor for the request parts (used in [DioxusServerContext]). This will extract the method, uri, query, and headers from the request. @@ -273,11 +291,20 @@ pub fn request_parts( }) } -fn with_ssr_state( - cfg: &ServeConfig

, -) -> impl Filter + Clone { +fn with_ssr_state( + cfg: &ServeConfig, + virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, +) -> impl Filter< + Extract = (( + SSRState, + Arc VirtualDom + Send + Sync + 'static>, + ),), + Error = std::convert::Infallible, +> + Clone { let renderer = SSRState::new(cfg); - warp::any().map(move || renderer.clone()) + let virtual_dom_factory = + Arc::new(virtual_dom_factory) as Arc VirtualDom + Send + Sync + 'static>; + warp::any().map(move || (renderer.clone(), virtual_dom_factory.clone())) } #[derive(Debug)] diff --git a/packages/fullstack/src/config.rs b/packages/fullstack/src/config.rs index fe9efe149..0135a149d 100644 --- a/packages/fullstack/src/config.rs +++ b/packages/fullstack/src/config.rs @@ -170,15 +170,19 @@ impl Config { let router = { // Serve the dist folder and the index.html file let serve_dir = warp::fs::dir(cfg.assets_path); + let build_virtual_dom = Arc::new(build_virtual_dom); router .or(connect_hot_reload()) // Then the index route - .or(warp::path::end().and(render_ssr(cfg.clone()))) + .or(warp::path::end().and(render_ssr(cfg.clone(), { + let build_virtual_dom = build_virtual_dom.clone(); + move || build_virtual_dom() + }))) // Then the static assets .or(serve_dir) // Then all other routes - .or(render_ssr(cfg)) + .or(render_ssr(cfg, move || build_virtual_dom())) }; warp::serve(router.boxed().with(warp::filters::compression::gzip())) .run(addr)