Browse Source

fix other fullstack adapters

Evan Almloff 1 year ago
parent
commit
89b1e56fc3

+ 0 - 5
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]]

+ 1 - 6
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!" }

+ 1 - 2
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::*;

+ 1 - 2
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)]

+ 4 - 9
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"]

+ 5 - 19
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<AppProps>) -> 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<AppProps>) -> 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<String, ServerFnError> {
     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);
 }

+ 20 - 10
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<P: Clone + serde::Serialize + Send + Sync + 'static>(
+    fn serve_dioxus_application(
         self,
         server_fn_path: &'static str,
-        cfg: impl Into<ServeConfig<P>>,
+        cfg: impl Into<ServeConfig>,
+        virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
     ) -> Self;
 }
 
@@ -281,10 +283,11 @@ impl DioxusRouterExt for Router {
         self
     }
 
-    fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
+    fn serve_dioxus_application(
         self,
         server_fn_path: &'static str,
-        cfg: impl Into<ServeConfig<P>>,
+        cfg: impl Into<ServeConfig>,
+        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<P: Clone> {
-    cfg: ServeConfig<P>,
+pub struct SSRHandler {
+    config: ServeConfig,
+    virtual_dom: Box<dyn Fn() -> VirtualDom + Send + Sync>,
 }
 
-impl<P: Clone> SSRHandler<P> {
+impl SSRHandler {
     /// Creates a new SSR handler with the given configuration.
-    pub fn new(cfg: ServeConfig<P>) -> 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<P: Clone + serde::Serialize + Send + Sync + 'static> Handler for SSRHandler<P> {
+impl Handler for SSRHandler {
     async fn handle(
         &self,
         req: &mut Request,

+ 67 - 40
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<P: Clone + serde::Serialize + Send + Sync + 'static>(
+pub fn serve_dioxus_application(
     server_fn_route: &'static str,
-    cfg: impl Into<ServeConfig<P>>,
+    cfg: impl Into<ServeConfig>,
+    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<dyn Fn() -> 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<P: Clone + serde::Serialize + Send + Sync + 'static>(
-    cfg: ServeConfig<P>,
+pub fn render_ssr(
+    cfg: ServeConfig,
+    virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
 ) -> impl Filter<Extract = (impl Reply,), Error = warp::Rejection> + 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<dyn Fn() -> 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());
-                        }
-                        freshness.write(headers_mut);
+                            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()
+                            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<P: Clone + serde::Serialize + Send + Sync + 'static>(
-    cfg: &ServeConfig<P>,
-) -> impl Filter<Extract = (SSRState,), Error = std::convert::Infallible> + Clone {
+fn with_ssr_state(
+    cfg: &ServeConfig,
+    virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static,
+) -> impl Filter<
+    Extract = ((
+        SSRState,
+        Arc<dyn Fn() -> 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<dyn Fn() -> VirtualDom + Send + Sync + 'static>;
+    warp::any().map(move || (renderer.clone(), virtual_dom_factory.clone()))
 }
 
 #[derive(Debug)]

+ 6 - 2
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)