From 0c532c5e0c8c41a33a88be4f8030797f556cf3af Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 17 Jan 2024 14:02:49 -0600 Subject: [PATCH] work on restoring fullstack --- Cargo.lock | 4 +- packages/fullstack/Cargo.toml | 8 +- packages/fullstack/README.md | 2 +- .../fullstack/examples/axum-auth/src/main.rs | 2 +- .../fullstack/examples/axum-router/Cargo.toml | 4 +- .../examples/static-hydrated/Cargo.toml | 4 +- .../examples/static-hydrated/src/main.rs | 6 +- .../fullstack/src/adapters/axum_adapter.rs | 20 ++-- .../fullstack/src/adapters/salvo_adapter.rs | 8 +- .../fullstack/src/adapters/warp_adapter.rs | 8 +- packages/fullstack/src/hooks/server_cached.rs | 2 +- packages/fullstack/src/hooks/server_future.rs | 62 ++++++------ packages/fullstack/src/hot_reload.rs | 4 +- packages/fullstack/src/launch.rs | 69 +++++-------- packages/fullstack/src/lib.rs | 4 - packages/fullstack/src/render.rs | 50 ++++------ packages/fullstack/src/router.rs | 98 ------------------- packages/fullstack/src/serve_config.rs | 43 +++----- packages/router/Cargo.toml | 2 + packages/router/src/router_cfg.rs | 76 ++++++++------ 20 files changed, 172 insertions(+), 304 deletions(-) delete mode 100644 packages/fullstack/src/router.rs diff --git a/Cargo.lock b/Cargo.lock index 5fd9b3e9e..710d6f778 100644 --- a/Cargo.lock +++ b/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", diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index 3b81c646b..cbf3d09e5 100644 --- a/packages/fullstack/Cargo.toml +++ b/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"] diff --git a/packages/fullstack/README.md b/packages/fullstack/README.md index 9d95a362a..ad54ff441 100644 --- a/packages/fullstack/README.md +++ b/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)) diff --git a/packages/fullstack/examples/axum-auth/src/main.rs b/packages/fullstack/examples/axum-auth/src/main.rs index 4380691ec..08150c6db 100644 --- a/packages/fullstack/examples/axum-auth/src/main.rs +++ b/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, diff --git a/packages/fullstack/examples/axum-router/Cargo.toml b/packages/fullstack/examples/axum-router/Cargo.toml index a06e20443..a0ebd888f 100644 --- a/packages/fullstack/examples/axum-router/Cargo.toml +++ b/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"] } diff --git a/packages/fullstack/examples/static-hydrated/Cargo.toml b/packages/fullstack/examples/static-hydrated/Cargo.toml index 97776dc54..889ff60b5 100644 --- a/packages/fullstack/examples/static-hydrated/Cargo.toml +++ b/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" diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index 14a58beb1..af72c642c 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/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::::default(), + ) .assets_path("docs") .incremental(IncrementalRendererConfig::default().static_dir("docs")) .build(), diff --git a/packages/fullstack/src/adapters/axum_adapter.rs b/packages/fullstack/src/adapters/axum_adapter.rs index 01f5d0a77..981a0c01d 100644 --- a/packages/fullstack/src/adapters/axum_adapter.rs +++ b/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 { /// /// # Example /// ```rust - /// use dioxus::prelude::*; + /// use dioxus_lib::prelude::*; /// use dioxus_fullstack::prelude::*; /// /// #[tokio::main] @@ -115,7 +115,7 @@ pub trait DioxusRouterExt { /// /// # Example /// ```rust - /// use dioxus::prelude::*; + /// use dioxus_lib::prelude::*; /// use dioxus_fullstack::prelude::*; /// /// #[tokio::main] @@ -163,7 +163,7 @@ pub trait DioxusRouterExt { /// # 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 { /// .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 { /// # 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 { /// .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( /// 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( /// /// #[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); diff --git a/packages/fullstack/src/adapters/salvo_adapter.rs b/packages/fullstack/src/adapters/salvo_adapter.rs index 2fcf2951b..0a3f9319f 100644 --- a/packages/fullstack/src/adapters/salvo_adapter.rs +++ b/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; diff --git a/packages/fullstack/src/adapters/warp_adapter.rs b/packages/fullstack/src/adapters/warp_adapter.rs index 863ae12ca..92a038d15 100644 --- a/packages/fullstack/src/adapters/warp_adapter.rs +++ b/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; /// } /// diff --git a/packages/fullstack/src/hooks/server_cached.rs b/packages/fullstack/src/hooks/server_cached.rs index 64be63825..959dbd406 100644 --- a/packages/fullstack/src/hooks/server_cached.rs +++ b/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 { diff --git a/packages/fullstack/src/hooks/server_future.rs b/packages/fullstack/src/hooks/server_future.rs index 48bc9962d..24cd7c0ae 100644 --- a/packages/fullstack/src/hooks/server_future.rs +++ b/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 { } impl UseServerFuture { - // /// 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)(); - // } + /// 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); - // } - // } + /// 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()) - // } + /// 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 { - // self.task.get() - // } + /// Get the ID of the future in Dioxus' internal scheduler + pub fn task(&self) -> Option { + self.task.get() + } - // /// Get the current state of the future. - // pub fn reloading(&self) -> bool { - // self.task.get().is_some() - // } + /// Get the current state of the future. + pub fn reloading(&self) -> bool { + self.task.get().is_some() + } } diff --git a/packages/fullstack/src/hot_reload.rs b/packages/fullstack/src/hot_reload.rs index e791a0eef..001894031 100644 --- a/packages/fullstack/src/hot_reload.rs +++ b/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>>, + pub(crate) templates: Arc>>, // The channel to send messages to the hot reload thread pub(crate) message_receiver: Receiver>, } diff --git a/packages/fullstack/src/launch.rs b/packages/fullstack/src/launch.rs index 5ebf14db4..e3a4cfa3f 100644 --- a/packages/fullstack/src/launch.rs +++ b/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::*; +use dioxus_lib::prelude::*; -/// A builder for a fullstack app. -pub struct LaunchBuilder { - component: Component, - #[cfg(not(feature = "ssr"))] - props: Props, +/// The desktop renderer platform +pub struct FullstackPlatform; + +impl dioxus_core::PlatformBuilder for FullstackPlatform { + type Config = Config; + + fn launch(config: dioxus_core::CrossPlatformConfig, 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, + server_cfg: ServeConfigBuilder, #[cfg(feature = "ssr")] addr: std::net::SocketAddr, #[cfg(feature = "web")] @@ -22,38 +26,29 @@ pub struct LaunchBuilder { desktop_cfg: dioxus_desktop::Config, } -impl - LaunchBuilder -{ - /// Create a new builder for a fullstack app. - pub fn new(component: Component) -> 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) -> 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) -> Self { + pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self { Self { server_cfg, ..self } } @@ -210,17 +205,3 @@ impl LaunchBuilder> -where - ::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::; - let props = crate::router::FullstackRouterConfig::default(); - Self::new_with_props(component, props) - } -} diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index 7ef582da1..3767a41c2 100644 --- a/packages/fullstack/src/lib.rs +++ b/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"))] diff --git a/packages/fullstack/src/render.rs b/packages/fullstack/src/render.rs index c3aefd605..dc0f9c93e 100644 --- a/packages/fullstack/src/render.rs +++ b/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>), @@ -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

, server_context: &'a DioxusServerContext, + app: Component

, + props: P, ) -> impl std::future::Future< Output = Result, > + 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 { - cfg: ServeConfig

, + component: Component

, + 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( - cfg: &crate::prelude::ServeConfig>, -) -> Result<(), dioxus_ssr::incremental::IncrementalRendererError> -where - Rt: dioxus_router::prelude::Routable + Send + Sync + Serialize, - ::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::(&mut renderer, &wrapper).await -} - struct WriteBuffer { buffer: Vec, } diff --git a/packages/fullstack/src/router.rs b/packages/fullstack/src/router.rs deleted file mode 100644 index f06c7bf8d..000000000 --- a/packages/fullstack/src/router.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! Fullstack router intigration -#![allow(non_snake_case)] -use dioxus::prelude::*; - -/// Used by the launch macro -#[doc(hidden)] -pub fn RouteWithCfg(props: FullstackRouterConfig) -> Element -where - R: dioxus_router::prelude::Routable, - ::Err: std::fmt::Display, -{ - use dioxus_router::prelude::RouterConfig; - - let cfg = props; - rsx! { - dioxus_router::prelude::Router:: { - 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 -where - R: dioxus_router::prelude::Routable, - ::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, -} - -impl Clone for FullstackRouterConfig -where - R: dioxus_router::prelude::Routable, - ::Err: std::fmt::Display, -{ - fn clone(&self) -> Self { - *self - } -} - -impl Copy for FullstackRouterConfig -where - R: dioxus_router::prelude::Routable, - ::Err: std::fmt::Display, -{ -} - -impl Default for FullstackRouterConfig -where - R: dioxus_router::prelude::Routable, - ::Err: std::fmt::Display, -{ - fn default() -> Self { - Self { - failure_external_navigation: dioxus_router::prelude::FailureExternalNavigation, - scroll_restoration: true, - phantom: std::marker::PhantomData, - } - } -} diff --git a/packages/fullstack/src/serve_config.rs b/packages/fullstack/src/serve_config.rs index 75a473c89..fb2bc9d03 100644 --- a/packages/fullstack/src/serve_config.rs +++ b/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 { - pub(crate) app: Component

, - 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 ServeConfigBuilder> -where - R: dioxus_router::prelude::Routable, - ::Err: std::fmt::Display, -{ - /// Create a new ServeConfigBuilder to serve a router on the server. - pub fn new_with_router(cfg: FullstackRouterConfig) -> Self { - Self::new(RouteWithCfg::, cfg) - } -} - -impl ServeConfigBuilder

{ +impl ServeConfigBuilder { /// Create a new ServeConfigBuilder with the root component and props to render on the server. - pub fn new(app: Component

, props: P) -> Self { + pub fn new() -> Self { Self { - app, - props, root_id: None, index_path: None, assets_path: None, @@ -91,7 +75,7 @@ impl ServeConfigBuilder

{ } /// Build the ServeConfig - pub fn build(self) -> ServeConfig

{ + pub fn build(self) -> ServeConfig { let assets_path = self.assets_path.unwrap_or("dist"); let index_path = self @@ -104,8 +88,6 @@ impl ServeConfigBuilder

{ 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 { - pub(crate) app: Component

, - pub(crate) props: P, +pub struct ServeConfig { pub(crate) index: IndexHtml, pub(crate) assets_path: &'static str, pub(crate) incremental: Option>, } -impl From> for ServeConfig

{ - fn from(builder: ServeConfigBuilder

) -> Self { +impl ServeConfig { + /// Create a new builder for a ServeConfig + pub fn builder() -> ServeConfigBuilder { + ServeConfigBuilder::new() + } +} + +impl From for ServeConfig { + fn from(builder: ServeConfigBuilder) -> Self { builder.build() } } diff --git a/packages/router/Cargo.toml b/packages/router/Cargo.toml index 702cfa7ec..49cef80da 100644 --- a/packages/router/Cargo.toml +++ b/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"] } diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index 6df2b73fe..dff8df761 100644 --- a/packages/router/src/router_cfg.rs +++ b/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::>>::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 RouterConfig where @@ -53,18 +90,13 @@ where R: serde::Serialize + serde::de::DeserializeOwned, { pub(crate) fn get_history(self) -> Box> { - self.history.unwrap_or_else(|| { - #[cfg(all(not(feature = "liveview"), target_arch = "wasm32", feature = "web"))] - let history = Box::>::default(); - #[cfg(all( - not(feature = "liveview"), - any(not(target_arch = "wasm32"), not(feature = "web")) - ))] - let history = Box::>::default(); - #[cfg(feature = "liveview")] - let history = Box::>::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 ::Err: std::fmt::Display, { pub(crate) fn take_history(&mut self) -> Box { - 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::>>::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)) } }