소스 검색

work on restoring fullstack

Evan Almloff 1 년 전
부모
커밋
0c532c5e0c

+ 2 - 2
Cargo.lock

@@ -2606,10 +2606,9 @@ dependencies = [
  "base64 0.21.7",
  "bytes",
  "ciborium",
- "dioxus-core",
  "dioxus-desktop",
  "dioxus-hot-reload",
- "dioxus-router",
+ "dioxus-lib",
  "dioxus-ssr",
  "dioxus-web",
  "dioxus_server_macro",
@@ -2829,6 +2828,7 @@ dependencies = [
  "dioxus",
  "dioxus-cli-config",
  "dioxus-desktop",
+ "dioxus-fullstack",
  "dioxus-lib",
  "dioxus-liveview",
  "dioxus-router",

+ 2 - 6
packages/fullstack/Cargo.toml

@@ -25,7 +25,7 @@ tower-http = { version = "0.4.0", optional = true, features = ["fs", "compressio
 salvo = { version = "0.63.0", optional = true, features = ["serve-static", "websocket", "compression"] }
 http-body-util = { version = "0.1.0-rc.2", optional = true }
 
-dioxus-core = { workspace = true }
+dioxus-lib = { workspace = true }
 
 # Dioxus + SSR
 dioxus-ssr = { workspace = true, optional = true }
@@ -38,9 +38,6 @@ dioxus-web = { workspace = true, features = ["hydrate"], optional = true }
 # Desktop Integration
 dioxus-desktop = { workspace = true, optional = true }
 
-# Router Integration
-dioxus-router = { workspace = true, optional = true }
-
 tracing = { workspace = true }
 tracing-futures = { workspace = true, optional = true }
 once_cell = "1.17.1"
@@ -70,13 +67,12 @@ web-sys = { version = "0.3.61", features = ["Window", "Document", "Element", "Ht
 
 [features]
 default = ["hot-reload"]
-router = ["dioxus-router"]
 hot-reload = ["serde_json", "futures-util"]
 web = ["dioxus-web"]
 desktop = ["dioxus-desktop"]
 warp = ["dep:warp", "ssr"]
 axum = ["dep:axum", "tower-http", "ssr"]
 salvo = ["dep:salvo", "ssr", "http-body-util"]
-ssr = ["server_fn/ssr", "dioxus_server_macro/ssr", "tokio", "tokio-util", "tokio-stream", "dioxus-ssr", "tower", "hyper", "http", "dioxus-router?/ssr", "tower-layer", "anymap", "tracing-futures", "pin-project", "thiserror"]
+ssr = ["server_fn/ssr", "dioxus_server_macro/ssr", "tokio", "tokio-util", "tokio-stream", "dioxus-ssr", "tower", "hyper", "http", "tower-layer", "anymap", "tracing-futures", "pin-project", "thiserror"]
 default-tls = ["server_fn/default-tls"]
 rustls = ["server_fn/rustls"]

+ 1 - 1
packages/fullstack/README.md

@@ -53,7 +53,7 @@ fn main() {
                     // Automatically handles server side rendering, hot reloading intigration, and hosting server functions
                     serve_dioxus_application(
                         "",
-                        ServeConfigBuilder::new(app, ()),
+                        ServerConfig::new(app, ()),
                     )
                 )
                 .run(([127, 0, 0, 1], 8080))

+ 1 - 1
packages/fullstack/examples/axum-auth/src/main.rs

@@ -51,7 +51,7 @@ fn main() {
                 // build our application with some routes
                 let app = Router::new()
                     // Server side render the application, serve static assets, and register server functions
-                    .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
+                    .serve_dioxus_application("", ServerConfig::new(app, ()))
                     .layer(
                         axum_session_auth::AuthSessionLayer::<
                             crate::auth::User,

+ 2 - 2
packages/fullstack/examples/axum-router/Cargo.toml

@@ -9,8 +9,8 @@ publish = false
 [dependencies]
 dioxus-web = { workspace = true, features = ["hydrate"], optional = true }
 dioxus = { workspace = true }
-dioxus-router = { workspace = true }
-dioxus-fullstack = { workspace = true, features = ["router"] }
+dioxus-router = { workspace = true, features = ["fullstack"]}
+dioxus-fullstack = { workspace = true }
 axum = { version = "0.6.12", optional = true }
 tokio = {workspace = true, features = ["full"], optional = true }
 serde = { version = "1.0.159", features = ["derive"] }

+ 2 - 2
packages/fullstack/examples/static-hydrated/Cargo.toml

@@ -9,8 +9,8 @@ publish = false
 [dependencies]
 dioxus-web = { workspace = true, features = ["hydrate"], optional = true }
 dioxus = { workspace = true }
-dioxus-fullstack = { workspace = true, features = ["router"] }
-dioxus-router = { workspace = true}
+dioxus-fullstack = { workspace = true }
+dioxus-router = { workspace = true, features = ["fullstack"] }
 tokio = { workspace = true, features = ["full"], optional = true }
 serde = "1.0.159"
 

+ 3 - 3
packages/fullstack/examples/static-hydrated/src/main.rs

@@ -16,9 +16,9 @@ use serde::{Deserialize, Serialize};
 #[tokio::main]
 async fn main() {
     pre_cache_static_routes_with_props(
-        &ServeConfigBuilder::new_with_router(dioxus_fullstack::router::FullstackRouterConfig::<
-            Route,
-        >::default())
+        &ServerConfig::new_with_router(
+            dioxus_fullstack::router::FullstackRouterConfig::<Route>::default(),
+        )
         .assets_path("docs")
         .incremental(IncrementalRendererConfig::default().static_dir("docs"))
         .build(),

+ 10 - 10
packages/fullstack/src/adapters/axum_adapter.rs

@@ -3,7 +3,7 @@
 //! # Example
 //! ```rust
 //! #![allow(non_snake_case)]
-//! use dioxus::prelude::*;
+//! use dioxus_lib::prelude::*;
 //! use dioxus_fullstack::prelude::*;
 //!
 //! fn main() {
@@ -20,7 +20,7 @@
 //!                     .serve(
 //!                         axum::Router::new()
 //!                             // Server side render the application, serve static assets, and register server functions
-//!                             .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
+//!                             .serve_dioxus_application("", ServerConfig::new(app, ()))
 //!                             .into_make_service(),
 //!                     )
 //!                     .await
@@ -78,7 +78,7 @@ pub trait DioxusRouterExt<S> {
     ///
     /// # Example
     /// ```rust
-    /// use dioxus::prelude::*;
+    /// use dioxus_lib::prelude::*;
     /// use dioxus_fullstack::prelude::*;
     ///
     /// #[tokio::main]
@@ -115,7 +115,7 @@ pub trait DioxusRouterExt<S> {
     ///
     /// # Example
     /// ```rust
-    /// use dioxus::prelude::*;
+    /// use dioxus_lib::prelude::*;
     /// use dioxus_fullstack::prelude::*;
     ///
     /// #[tokio::main]
@@ -163,7 +163,7 @@ pub trait DioxusRouterExt<S> {
     /// # Example
     /// ```rust
     /// #![allow(non_snake_case)]
-    /// use dioxus::prelude::*;
+    /// use dioxus_lib::prelude::*;
     /// use dioxus_fullstack::prelude::*;
     ///
     /// #[tokio::main]
@@ -173,7 +173,7 @@ pub trait DioxusRouterExt<S> {
     ///         .serve(
     ///             axum::Router::new()
     ///                 // Server side render the application, serve static assets, and register server functions
-    ///                 .serve_static_assets(ServeConfigBuilder::new(app, ()))
+    ///                 .serve_static_assets("dist")
     ///                 // Server render the application
     ///                 // ...
     ///                 .into_make_service(),
@@ -194,7 +194,7 @@ pub trait DioxusRouterExt<S> {
     /// # Example
     /// ```rust
     /// #![allow(non_snake_case)]
-    /// use dioxus::prelude::*;
+    /// use dioxus_lib::prelude::*;
     /// use dioxus_fullstack::prelude::*;
     ///
     /// #[tokio::main]
@@ -204,7 +204,7 @@ pub trait DioxusRouterExt<S> {
     ///         .serve(
     ///             axum::Router::new()
     ///                 // Server side render the application, serve static assets, and register server functions
-    ///                 .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
+    ///                 .serve_dioxus_application("", ServerConfig::new(app, ()))
     ///                 .into_make_service(),
     ///         )
     ///         .await
@@ -376,7 +376,7 @@ fn apply_request_parts_to_response<B>(
 /// use std::sync::{Arc, Mutex};
 ///
 /// use axum::routing::get;
-/// use dioxus::prelude::*;
+/// use dioxus_lib::prelude::*;
 /// use dioxus_fullstack::{axum_adapter::render_handler_with_context, prelude::*};
 ///
 /// fn app() -> Element {
@@ -387,7 +387,7 @@ fn apply_request_parts_to_response<B>(
 ///
 /// #[tokio::main]
 /// async fn main() {
-///     let cfg = ServeConfigBuilder::new(app, ())
+///     let cfg = ServerConfig::new(app, ())
 ///         .assets_path("dist")
 ///         .build();
 ///     let ssr_state = SSRState::new(&cfg);

+ 4 - 4
packages/fullstack/src/adapters/salvo_adapter.rs

@@ -3,7 +3,7 @@
 //! # Example
 //! ```rust
 //! #![allow(non_snake_case)]
-//! use dioxus::prelude::*;
+//! use dioxus_lib::prelude::*;
 //! use dioxus_fullstack::prelude::*;
 //!
 //! fn main() {
@@ -16,7 +16,7 @@
 //!             .unwrap()
 //!             .block_on(async move {
 //!                 let router =
-//!                     Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ()));
+//!                     Router::new().serve_dioxus_application("", ServerConfig::new(app, ()));
 //!                 Server::new(TcpListener::bind("127.0.0.1:8080"))
 //!                     .serve(router)
 //!                     .await;
@@ -186,14 +186,14 @@ pub trait DioxusRouterExt {
     /// # Example
     /// ```rust
     /// #![allow(non_snake_case)]
-    /// use dioxus::prelude::*;
+    /// use dioxus_lib::prelude::*;
     /// use dioxus_fullstack::prelude::*;
     /// use salvo::prelude::*;
     /// use std::{net::TcpListener, sync::Arc};
     ///
     /// #[tokio::main]
     /// async fn main() {
-    ///     let router = Router::new().serve_dioxus_application("", ServeConfigBuilder::new(app, ()));
+    ///     let router = Router::new().serve_dioxus_application("", ServerConfig::new(app, ()));
     ///     Server::new(TcpListener::bind("127.0.0.1:8080"))
     ///         .serve(router)
     ///         .await;

+ 4 - 4
packages/fullstack/src/adapters/warp_adapter.rs

@@ -3,7 +3,7 @@
 //! # Example
 //! ```rust
 //! #![allow(non_snake_case)]
-//! use dioxus::prelude::*;
+//! use dioxus_lib::prelude::*;
 //! use dioxus_fullstack::prelude::*;
 //!
 //! fn main() {
@@ -14,7 +14,7 @@
 //!         tokio::runtime::Runtime::new()
 //!             .unwrap()
 //!             .block_on(async move {
-//!                 let routes = serve_dioxus_application("", ServeConfigBuilder::new(app, ()));
+//!                 let routes = serve_dioxus_application("", ServerConfig::new(app, ()));
 //!                 warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
 //!             });
 //!     }
@@ -166,12 +166,12 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R
 /// # Example
 /// ```rust
 /// #![allow(non_snake_case)]
-/// use dioxus::prelude::*;
+/// use dioxus_lib::prelude::*;
 /// use dioxus_fullstack::prelude::*;
 ///
 /// #[tokio::main]
 /// async fn main() {
-///     let routes = serve_dioxus_application("", ServeConfigBuilder::new(app, ()));
+///     let routes = serve_dioxus_application("", ServerConfig::new(app, ()));
 ///     warp::serve(routes).run(([127, 0, 0, 1], 8080)).await;
 /// }
 ///

+ 1 - 1
packages/fullstack/src/hooks/server_cached.rs

@@ -8,7 +8,7 @@ use serde::{de::DeserializeOwned, Serialize};
 ///
 /// # Example
 /// ```rust
-/// use dioxus::prelude::*;
+/// use dioxus_lib::prelude::*;
 /// use dioxus_fullstack::prelude::*;
 ///
 /// fn app() -> Element {

+ 35 - 35
packages/fullstack/src/hooks/server_future.rs

@@ -1,4 +1,4 @@
-use dioxus_core::prelude::*;
+use dioxus_lib::prelude::*;
 use serde::{de::DeserializeOwned, Serialize};
 use std::any::Any;
 use std::cell::Cell;
@@ -70,10 +70,10 @@ where
 
     //     // Cancel the current future
     //     if let Some(current) = state.task.take() {
-    //         cx.remove_future(current);
+    //         remove_future(current);
     //     }
 
-    //     state.task.set(Some(cx.push_future(async move {
+    //     state.task.set(Some(push_future(async move {
     //         let data;
     //         #[cfg(feature = "ssr")]
     //         {
@@ -115,36 +115,36 @@ pub struct UseServerFuture<T> {
 }
 
 impl<T> UseServerFuture<T> {
-    // /// Restart the future with new dependencies.
-    // ///
-    // /// Will not cancel the previous future, but will ignore any values that it
-    // /// generates.
-    // pub fn restart(&self) {
-    //     self.needs_regen.set(true);
-    //     (self.update)();
-    // }
-
-    // /// Forcefully cancel a future
-    // pub fn cancel(&self) {
-    //     if let Some(task) = self.task.take() {
-    //         cx.remove_future(task);
-    //     }
-    // }
-
-    // /// Return any value, even old values if the future has not yet resolved.
-    // ///
-    // /// If the future has never completed, the returned value will be `None`.
-    // pub fn value(&self) -> Ref<'_, T> {
-    //     Ref::map(self.value.borrow(), |v| v.as_deref().unwrap())
-    // }
-
-    // /// Get the ID of the future in Dioxus' internal scheduler
-    // pub fn task(&self) -> Option<Task> {
-    //     self.task.get()
-    // }
-
-    // /// Get the current state of the future.
-    // pub fn reloading(&self) -> bool {
-    //     self.task.get().is_some()
-    // }
+    /// Restart the future with new dependencies.
+    ///
+    /// Will not cancel the previous future, but will ignore any values that it
+    /// generates.
+    pub fn restart(&self) {
+        self.needs_regen.set(true);
+        (self.update)();
+    }
+
+    /// Forcefully cancel a future
+    pub fn cancel(&self) {
+        if let Some(task) = self.task.take() {
+            remove_future(task);
+        }
+    }
+
+    /// Return any value, even old values if the future has not yet resolved.
+    ///
+    /// If the future has never completed, the returned value will be `None`.
+    pub fn value(&self) -> Ref<'_, T> {
+        Ref::map(self.value.borrow(), |v| v.as_deref().unwrap())
+    }
+
+    /// Get the ID of the future in Dioxus' internal scheduler
+    pub fn task(&self) -> Option<Task> {
+        self.task.get()
+    }
+
+    /// Get the current state of the future.
+    pub fn reloading(&self) -> bool {
+        self.task.get().is_some()
+    }
 }

+ 2 - 2
packages/fullstack/src/hot_reload.rs

@@ -1,6 +1,6 @@
 use std::sync::Arc;
 
-use dioxus::prelude::Template;
+use dioxus_lib::prelude::Template;
 use tokio::sync::{
     watch::{channel, Receiver},
     RwLock,
@@ -9,7 +9,7 @@ use tokio::sync::{
 #[derive(Clone)]
 pub struct HotReloadState {
     // The cache of all templates that have been modified since the last time we checked
-    pub(crate) templates: Arc<RwLock<std::collections::HashSet<dioxus::prelude::Template>>>,
+    pub(crate) templates: Arc<RwLock<std::collections::HashSet<dioxus_lib::prelude::Template>>>,
     // The channel to send messages to the hot reload thread
     pub(crate) message_receiver: Receiver<Option<Template>>,
 }

+ 26 - 45
packages/fullstack/src/launch.rs

@@ -1,19 +1,23 @@
 //! Launch helper macros for fullstack apps
 #![allow(unused)]
 use crate::prelude::*;
-use dioxus_core::prelude::*;
-#[cfg(feature = "router")]
-use dioxus_router::prelude::*;
-
-/// A builder for a fullstack app.
-pub struct LaunchBuilder<Props: Clone> {
-    component: Component<Props>,
-    #[cfg(not(feature = "ssr"))]
-    props: Props,
+use dioxus_lib::prelude::*;
+
+/// The desktop renderer platform
+pub struct FullstackPlatform;
+
+impl<Props: Clone + 'static> dioxus_core::PlatformBuilder<Props> for FullstackPlatform {
+    type Config = Config;
+
+    fn launch(config: dioxus_core::CrossPlatformConfig<Props>, platform_config: Self::Config) {}
+}
+
+/// Settings for a fullstack app.
+pub struct Config {
     #[cfg(feature = "ssr")]
     server_fn_route: &'static str,
     #[cfg(feature = "ssr")]
-    server_cfg: ServeConfigBuilder<Props>,
+    server_cfg: ServeConfigBuilder,
     #[cfg(feature = "ssr")]
     addr: std::net::SocketAddr,
     #[cfg(feature = "web")]
@@ -22,38 +26,29 @@ pub struct LaunchBuilder<Props: Clone> {
     desktop_cfg: dioxus_desktop::Config,
 }
 
-impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static>
-    LaunchBuilder<Props>
-{
-    /// Create a new builder for a fullstack app.
-    pub fn new(component: Component<Props>) -> Self
-    where
-        Props: Default,
-    {
-        Self::new_with_props(component, Default::default())
-    }
-
-    /// Create a new builder for a fullstack app with props.
-    pub fn new_with_props(component: Component<Props>, props: Props) -> Self
-    where
-        Props: Default,
-    {
+#[allow(clippy::derivable_impls)]
+impl Default for Config {
+    fn default() -> Self {
         Self {
-            component,
-            #[cfg(not(feature = "ssr"))]
-            props,
             #[cfg(feature = "ssr")]
             server_fn_route: "",
             #[cfg(feature = "ssr")]
             addr: std::net::SocketAddr::from(([127, 0, 0, 1], 8080)),
             #[cfg(feature = "ssr")]
-            server_cfg: ServeConfigBuilder::new(component, props),
+            server_cfg: ServeConfigBuilder::new(),
             #[cfg(feature = "web")]
             web_cfg: dioxus_web::Config::default(),
             #[cfg(feature = "desktop")]
             desktop_cfg: dioxus_desktop::Config::default(),
         }
     }
+}
+
+impl Config {
+    /// Create a new config for a fullstack app.
+    pub fn new() -> Self {
+        Self::default()
+    }
 
     /// Set the address to serve the app on.
     #[cfg(feature = "ssr")]
@@ -82,7 +77,7 @@ impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync
 
     /// Set the server config.
     #[cfg(feature = "ssr")]
-    pub fn server_cfg(self, server_cfg: ServeConfigBuilder<Props>) -> Self {
+    pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self {
         Self { server_cfg, ..self }
     }
 
@@ -210,17 +205,3 @@ impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync
         }
     }
 }
-
-#[cfg(feature = "router")]
-impl<R: Routable> LaunchBuilder<crate::router::FullstackRouterConfig<R>>
-where
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-    R: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static,
-{
-    /// Create a new launch builder for the given router.
-    pub fn router() -> Self {
-        let component = crate::router::RouteWithCfg::<R>;
-        let props = crate::router::FullstackRouterConfig::default();
-        Self::new_with_props(component, props)
-    }
-}

+ 0 - 4
packages/fullstack/src/lib.rs

@@ -7,9 +7,6 @@ pub use once_cell;
 
 mod html_storage;
 
-#[cfg(feature = "router")]
-pub mod router;
-
 #[cfg(feature = "ssr")]
 mod adapters;
 #[cfg(feature = "ssr")]
@@ -39,7 +36,6 @@ pub mod prelude {
     use crate::hooks;
     #[cfg(not(feature = "ssr"))]
     pub use crate::html_storage::deserialize::get_root_props_from_document;
-    pub use crate::launch::LaunchBuilder;
     #[cfg(feature = "ssr")]
     pub use crate::layer::{Layer, Service};
     #[cfg(all(feature = "ssr", feature = "router"))]

+ 17 - 33
packages/fullstack/src/render.rs

@@ -1,19 +1,19 @@
 //! A shared pool of renderers for efficient server side rendering.
 
-use std::sync::Arc;
-
+use crate::render::dioxus_core::NoOpMutations;
 use crate::server_context::SERVER_CONTEXT;
-use dioxus::prelude::VirtualDom;
+use dioxus_lib::prelude::VirtualDom;
 use dioxus_ssr::{
     incremental::{IncrementalRendererConfig, RenderFreshness, WrapBody},
     Renderer,
 };
 use serde::Serialize;
+use std::sync::Arc;
 use std::sync::RwLock;
 use tokio::task::spawn_blocking;
 
 use crate::prelude::*;
-use dioxus::prelude::*;
+use dioxus_lib::prelude::*;
 
 enum SsrRendererPool {
     Renderer(RwLock<Vec<Renderer>>),
@@ -45,15 +45,17 @@ impl SsrRendererPool {
                         .expect("couldn't spawn runtime")
                         .block_on(async move {
                             let mut vdom = VirtualDom::new_with_props(component, props);
-                            // Make sure the evaluator is initialized
-                            dioxus_ssr::eval::init_eval(vdom.base_scope());
+                            vdom.in_runtime(|| {
+                                // Make sure the evaluator is initialized
+                                dioxus_ssr::eval::init_eval();
+                            });
                             let mut to = WriteBuffer { buffer: Vec::new() };
                             // before polling the future, we need to set the context
                             let prev_context =
                                 SERVER_CONTEXT.with(|ctx| ctx.replace(server_context));
                             // poll the future, which may call server_context()
                             tracing::info!("Rebuilding vdom");
-                            let _ = vdom.rebuild();
+                            let _ = vdom.rebuild(&mut NoOpMutations);
                             vdom.wait_for_suspense().await;
                             tracing::info!("Suspense resolved");
                             // after polling the future, we need to restore the context
@@ -119,7 +121,7 @@ impl SsrRendererPool {
                                                 .with(|ctx| ctx.replace(Box::new(server_context)));
                                             // poll the future, which may call server_context()
                                             tracing::info!("Rebuilding vdom");
-                                            let _ = vdom.rebuild();
+                                            let _ = vdom.rebuild(&mut NoOpMutations);
                                             vdom.wait_for_suspense().await;
                                             tracing::info!("Suspense resolved");
                                             // after polling the future, we need to restore the context
@@ -195,16 +197,18 @@ impl SSRState {
         route: String,
         cfg: &'a ServeConfig<P>,
         server_context: &'a DioxusServerContext,
+        app: Component<P>,
+        props: P,
     ) -> impl std::future::Future<
         Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
     > + Send
            + 'a {
         async move {
-            let ServeConfig { app, props, .. } = cfg;
+            let ServeConfig { .. } = cfg;
 
             let (freshness, html) = self
                 .renderers
-                .render_to(cfg, route, *app, props.clone(), server_context)
+                .render_to(cfg, route, app, props, server_context)
                 .await?;
 
             Ok(RenderResponse { html, freshness })
@@ -213,7 +217,9 @@ impl SSRState {
 }
 
 struct FullstackRenderer<P: Clone + Send + Sync + 'static> {
-    cfg: ServeConfig<P>,
+    component: Component<P>,
+    props: P,
+    cfg: ServeConfig,
     server_context: DioxusServerContext,
 }
 
@@ -338,28 +344,6 @@ fn incremental_pre_renderer(
     renderer
 }
 
-#[cfg(all(feature = "ssr", feature = "router"))]
-/// Pre-caches all static routes
-pub async fn pre_cache_static_routes_with_props<Rt>(
-    cfg: &crate::prelude::ServeConfig<crate::router::FullstackRouterConfig<Rt>>,
-) -> Result<(), dioxus_ssr::incremental::IncrementalRendererError>
-where
-    Rt: dioxus_router::prelude::Routable + Send + Sync + Serialize,
-    <Rt as std::str::FromStr>::Err: std::fmt::Display,
-{
-    let wrapper = FullstackRenderer {
-        cfg: cfg.clone(),
-        server_context: Default::default(),
-    };
-    let mut renderer = incremental_pre_renderer(
-        cfg.incremental
-            .as_ref()
-            .expect("incremental renderer config must be set to pre-cache static routes"),
-    );
-
-    dioxus_router::incremental::pre_cache_static_routes::<Rt, _>(&mut renderer, &wrapper).await
-}
-
 struct WriteBuffer {
     buffer: Vec<u8>,
 }

+ 0 - 98
packages/fullstack/src/router.rs

@@ -1,98 +0,0 @@
-//! Fullstack router intigration
-#![allow(non_snake_case)]
-use dioxus::prelude::*;
-
-/// Used by the launch macro
-#[doc(hidden)]
-pub fn RouteWithCfg<R>(props: FullstackRouterConfig<R>) -> Element
-where
-    R: dioxus_router::prelude::Routable,
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-{
-    use dioxus_router::prelude::RouterConfig;
-
-    let cfg = props;
-    rsx! {
-        dioxus_router::prelude::Router::<R> {
-            config: move || {
-                RouterConfig::default()
-                    .failure_external_navigation(cfg.failure_external_navigation)
-                    .history({
-                        #[cfg(feature = "ssr")]
-                        let history = dioxus_router::prelude::MemoryHistory::with_initial_path(
-                            crate::prelude::server_context()
-                                .request_parts()
-                                .unwrap()
-                                .uri
-                                .to_string()
-                                .parse()
-                                .unwrap_or_else(|err| {
-                                    tracing::error!("Failed to parse uri: {}", err);
-                                    "/"
-                                        .parse()
-                                        .unwrap_or_else(|err| {
-                                            panic!("Failed to parse uri: {}", err);
-                                        })
-                                }),
-                        );
-                        #[cfg(not(feature = "ssr"))]
-                        let history = dioxus_router::prelude::WebHistory::new(
-                            None,
-                            cfg.scroll_restoration,
-                        );
-                        history
-                    })
-            }
-        }
-    }
-}
-
-fn default_external_navigation_handler() -> fn() -> Element {
-    dioxus_router::prelude::FailureExternalNavigation
-}
-
-/// The configuration for the router
-#[derive(Props, serde::Serialize, serde::Deserialize)]
-pub struct FullstackRouterConfig<R>
-where
-    R: dioxus_router::prelude::Routable,
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-{
-    #[serde(skip)]
-    #[serde(default = "default_external_navigation_handler")]
-    failure_external_navigation: fn() -> Element,
-    scroll_restoration: bool,
-    #[serde(skip)]
-    phantom: std::marker::PhantomData<R>,
-}
-
-impl<R> Clone for FullstackRouterConfig<R>
-where
-    R: dioxus_router::prelude::Routable,
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-{
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-impl<R> Copy for FullstackRouterConfig<R>
-where
-    R: dioxus_router::prelude::Routable,
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-{
-}
-
-impl<R> Default for FullstackRouterConfig<R>
-where
-    R: dioxus_router::prelude::Routable,
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-{
-    fn default() -> Self {
-        Self {
-            failure_external_navigation: dioxus_router::prelude::FailureExternalNavigation,
-            scroll_restoration: true,
-            phantom: std::marker::PhantomData,
-        }
-    }
-}

+ 15 - 28
packages/fullstack/src/serve_config.rs

@@ -7,13 +7,11 @@ use std::fs::File;
 use std::io::Read;
 use std::path::PathBuf;
 
-use dioxus::prelude::*;
+use dioxus_lib::prelude::*;
 
 /// A ServeConfig is used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`].
 #[derive(Clone)]
-pub struct ServeConfigBuilder<P: Clone> {
-    pub(crate) app: Component<P>,
-    pub(crate) props: P,
+pub struct ServeConfigBuilder {
     pub(crate) root_id: Option<&'static str>,
     pub(crate) index_path: Option<&'static str>,
     pub(crate) assets_path: Option<&'static str>,
@@ -41,24 +39,10 @@ impl dioxus_ssr::incremental::WrapBody for EmptyIncrementalRenderTemplate {
     }
 }
 
-#[cfg(feature = "router")]
-impl<R> ServeConfigBuilder<FullstackRouterConfig<R>>
-where
-    R: dioxus_router::prelude::Routable,
-    <R as std::str::FromStr>::Err: std::fmt::Display,
-{
-    /// Create a new ServeConfigBuilder to serve a router on the server.
-    pub fn new_with_router(cfg: FullstackRouterConfig<R>) -> Self {
-        Self::new(RouteWithCfg::<R>, cfg)
-    }
-}
-
-impl<P: Clone> ServeConfigBuilder<P> {
+impl ServeConfigBuilder {
     /// Create a new ServeConfigBuilder with the root component and props to render on the server.
-    pub fn new(app: Component<P>, props: P) -> Self {
+    pub fn new() -> Self {
         Self {
-            app,
-            props,
             root_id: None,
             index_path: None,
             assets_path: None,
@@ -91,7 +75,7 @@ impl<P: Clone> ServeConfigBuilder<P> {
     }
 
     /// Build the ServeConfig
-    pub fn build(self) -> ServeConfig<P> {
+    pub fn build(self) -> ServeConfig {
         let assets_path = self.assets_path.unwrap_or("dist");
 
         let index_path = self
@@ -104,8 +88,6 @@ impl<P: Clone> ServeConfigBuilder<P> {
         let index = load_index_html(index_path, root_id);
 
         ServeConfig {
-            app: self.app,
-            props: self.props,
             index,
             assets_path,
             incremental: self.incremental,
@@ -146,17 +128,22 @@ pub(crate) struct IndexHtml {
 /// Used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`].
 /// See [`ServeConfigBuilder`] to create a ServeConfig
 #[derive(Clone)]
-pub struct ServeConfig<P: Clone> {
-    pub(crate) app: Component<P>,
-    pub(crate) props: P,
+pub struct ServeConfig {
     pub(crate) index: IndexHtml,
     pub(crate) assets_path: &'static str,
     pub(crate) incremental:
         Option<std::sync::Arc<dioxus_ssr::incremental::IncrementalRendererConfig>>,
 }
 
-impl<P: Clone> From<ServeConfigBuilder<P>> for ServeConfig<P> {
-    fn from(builder: ServeConfigBuilder<P>) -> Self {
+impl ServeConfig {
+    /// Create a new builder for a ServeConfig
+    pub fn builder() -> ServeConfigBuilder {
+        ServeConfigBuilder::new()
+    }
+}
+
+impl From<ServeConfigBuilder> for ServeConfig {
+    fn from(builder: ServeConfigBuilder) -> Self {
         builder.build()
     }
 }

+ 2 - 0
packages/router/Cargo.toml

@@ -26,6 +26,7 @@ js-sys = { version = "0.3.63", optional = true }
 gloo-utils = { version = "0.1.6", optional = true }
 dioxus-liveview = { workspace = true, optional = true }
 dioxus-ssr = { workspace = true, optional = true }
+dioxus-fullstack = { workspace = true, optional = true }
 tokio = { workspace = true, features = ["full"], optional = true }
 dioxus-cli-config.workspace = true
 
@@ -36,6 +37,7 @@ liveview = ["dioxus-liveview", "tokio", "dep:serde", "serde_json"]
 wasm_test = []
 serde = ["dep:serde", "gloo-utils?/serde"]
 web = ["gloo", "web-sys", "wasm-bindgen", "gloo-utils", "js-sys"]
+fullstack = ["dioxus-fullstack"]
 
 [dev-dependencies]
 axum = { version = "0.6.1", features = ["ws"] }

+ 48 - 28
packages/router/src/router_cfg.rs

@@ -46,6 +46,43 @@ where
     }
 }
 
+macro_rules! default_history {
+    ($initial_route:ident) => {
+        {
+            // If we are on wasm32 and the web feature is enabled, use the web history.
+            #[cfg(all(target_arch = "wasm32", feature = "web"))]
+            return Box::<AnyHistoryProviderImplWrapper::<WebHistory::<R>>>::default();
+            // If we are using dioxus fullstack and the ssr feature is enabled, use the memory history with the initial path set to the current path in fullstack
+            #[cfg(all(feature = "fullstack", feature = "ssr"))]
+            return dioxus_router::prelude::MemoryHistory::with_initial_path(
+                dioxus_fullstack::prelude::server_context()
+                    .request_parts()
+                    .unwrap()
+                    .uri
+                    .to_string()
+                    .parse()
+                    .unwrap_or_else(|err| {
+                        tracing::error!("Failed to parse uri: {}", err);
+                        "/"
+                            .parse()
+                            .unwrap_or_else(|err| {
+                                panic!("Failed to parse uri: {}", err);
+                            })
+                    }),
+            );
+            // If we are not on wasm32 and the liveview feature is enabled, use the liveview history.
+            #[cfg(all(feature = "liveview"))]
+            return Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new($initial_route)));
+            // Otherwise use the memory history.
+            #[cfg(all(
+                not(all(target_arch = "wasm32", feature = "web")),
+                not(all(feature = "liveview", not(target_arch = "wasm32"))),
+            ))]
+            Box::new(AnyHistoryProviderImplWrapper::new(MemoryHistory::with_initial_path($initial_route)))
+        }
+    };
+}
+
 #[cfg(feature = "serde")]
 impl<R: Routable + Clone> RouterConfig<R>
 where
@@ -53,18 +90,13 @@ where
     R: serde::Serialize + serde::de::DeserializeOwned,
 {
     pub(crate) fn get_history(self) -> Box<dyn HistoryProvider<R>> {
-        self.history.unwrap_or_else(|| {
-            #[cfg(all(not(feature = "liveview"), target_arch = "wasm32", feature = "web"))]
-            let history = Box::<WebHistory<R>>::default();
-            #[cfg(all(
-                not(feature = "liveview"),
-                any(not(target_arch = "wasm32"), not(feature = "web"))
-            ))]
-            let history = Box::<MemoryHistory<R>>::default();
-            #[cfg(feature = "liveview")]
-            let history = Box::<LiveviewHistory<R>>::default();
-            history
-        })
+        #[allow(unused)]
+            let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err|
+                panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err)
+            ));
+        self.history
+            .take()
+            .unwrap_or_else(|| default_history!(initial_route))
     }
 }
 
@@ -89,25 +121,13 @@ where
     <R as std::str::FromStr>::Err: std::fmt::Display,
 {
     pub(crate) fn take_history(&mut self) -> Box<dyn AnyHistoryProvider> {
-        self.history.take().unwrap_or_else(|| {
-            #[allow(unused)]
+        #[allow(unused)]
             let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err|
                 panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err)
             ));
-            // If we are on wasm32 and the web feature is enabled, use the web history.
-            #[cfg(all(target_arch = "wasm32", feature = "web"))]
-            let history = Box::<AnyHistoryProviderImplWrapper::<WebHistory::<R>>>::default();
-            // If we are not on wasm32 and the liveview feature is enabled, use the liveview history.
-            #[cfg(all(feature = "liveview", not(target_arch = "wasm32")))]
-            let history = Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new(initial_route)));
-            // If neither of the above are true, use the memory history.
-            #[cfg(all(
-                not(all(target_arch = "wasm32", feature = "web")),
-                not(all(feature = "liveview", not(target_arch = "wasm32"))),
-            ))]
-            let history = Box::new(AnyHistoryProviderImplWrapper::new(MemoryHistory::with_initial_path(initial_route)));
-            history
-        })
+        self.history
+            .take()
+            .unwrap_or_else(|| default_history!(initial_route))
     }
 }