瀏覽代碼

make fullstack hello world compile

Evan Almloff 1 年之前
父節點
當前提交
ae3e167cfe

+ 1 - 1
Cargo.lock

@@ -787,7 +787,6 @@ name = "axum-hello-world"
 version = "0.1.0"
 dependencies = [
  "dioxus",
- "dioxus-fullstack",
  "reqwest",
  "serde",
  "simple_logger",
@@ -2363,6 +2362,7 @@ dependencies = [
  "env_logger",
  "futures-util",
  "rand 0.8.5",
+ "serde",
  "thiserror",
  "tokio",
  "tracing",

+ 1 - 1
packages/config-macro/src/lib.rs

@@ -7,7 +7,7 @@ use proc_macro2::TokenStream as TokenStream2;
 use quote::quote;
 
 #[proc_macro]
-pub fn server(input: TokenStream) -> TokenStream {
+pub fn server_only(input: TokenStream) -> TokenStream {
     if cfg!(any(feature = "ssr", feature = "liveview")) {
         let input = TokenStream2::from(input);
         quote! {

+ 39 - 16
packages/core/src/any_props.rs

@@ -5,28 +5,16 @@ pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
 
 /// A trait for a component that can be rendered.
 pub trait AnyProps: 'static {
+    /// Render the component with the internal props.
     fn render(&self) -> RenderReturn;
+    /// Check if the props are the same as the type erased props of another component.
     fn memoize(&self, other: &dyn Any) -> bool;
+    /// Get the props as a type erased `dyn Any`.
     fn props(&self) -> &dyn Any;
+    /// Duplicate this component into a new boxed component.
     fn duplicate(&self) -> BoxedAnyProps;
 }
 
-/// Create a new boxed props object.
-pub(crate) fn new_any_props<F: ComponentFunction<P, M>, P: Clone + 'static, M: 'static>(
-    render_fn: F,
-    memo: fn(&P, &P) -> bool,
-    props: P,
-    name: &'static str,
-) -> VProps<F, P, M> {
-    VProps {
-        render_fn,
-        memo,
-        props,
-        name,
-        phantom: std::marker::PhantomData,
-    }
-}
-
 /// A component along with the props the component uses to render.
 pub struct VProps<F: ComponentFunction<P, M>, P, M> {
     render_fn: F,
@@ -36,6 +24,41 @@ pub struct VProps<F: ComponentFunction<P, M>, P, M> {
     phantom: std::marker::PhantomData<M>,
 }
 
+impl<F: ComponentFunction<P, M>, P: Clone, M> Clone for VProps<F, P, M> {
+    fn clone(&self) -> Self {
+        Self {
+            render_fn: self.render_fn.clone(),
+            memo: self.memo,
+            props: self.props.clone(),
+            name: self.name,
+            phantom: std::marker::PhantomData,
+        }
+    }
+}
+
+impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> VProps<F, P, M> {
+    /// Create a [`VProps`] object.
+    pub fn new(
+        render_fn: F,
+        memo: fn(&P, &P) -> bool,
+        props: P,
+        name: &'static str,
+    ) -> VProps<F, P, M> {
+        VProps {
+            render_fn,
+            memo,
+            props,
+            name,
+            phantom: std::marker::PhantomData,
+        }
+    }
+
+    /// Get the current props of the VProps object
+    pub fn props(&self) -> &P {
+        &self.props
+    }
+}
+
 impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> AnyProps
     for VProps<F, P, M>
 {

+ 2 - 5
packages/core/src/nodes.rs

@@ -1,7 +1,4 @@
-use crate::{
-    any_props::{new_any_props, BoxedAnyProps},
-    innerlude::ScopeState,
-};
+use crate::{any_props::BoxedAnyProps, innerlude::ScopeState, VProps};
 use crate::{arena::ElementId, Element, Event};
 use crate::{
     innerlude::{ElementRef, EventHandler, MountId},
@@ -529,7 +526,7 @@ impl VComponent {
         P: Properties + 'static,
     {
         let render_fn = component.id();
-        let props = Box::new(new_any_props(
+        let props = Box::new(VProps::new(
             component,
             <P as Properties>::memoize,
             props,

+ 19 - 20
packages/core/src/platform.rs

@@ -1,7 +1,7 @@
 use std::any::Any;
 
 use crate::{
-    any_props::{new_any_props, AnyProps, VProps},
+    any_props::{AnyProps, VProps},
     properties::ComponentFunction,
     VirtualDom,
 };
@@ -44,38 +44,37 @@ impl<T: Any + Clone> ClonableAny for T {
 }
 
 /// The platform-independent part of the config needed to launch an application.
+#[derive(Clone)]
 pub struct CrossPlatformConfig<P: AnyProps> {
     /// The root component function.
-    component: P,
-    /// The contexts to provide to the root component.
-    root_contexts: Vec<BoxedContext>,
+    props: P,
+    // /// The contexts to provide to the root component.
+    // root_contexts: Vec<BoxedContext>,
 }
 
-impl<F: ComponentFunction<Props, M>, Props: Clone + 'static, M: 'static>
-    CrossPlatformConfig<VProps<F, Props, M>>
-{
+impl<P: AnyProps> CrossPlatformConfig<P> {}
+
+impl<P: AnyProps> CrossPlatformConfig<P> {
     /// Create a new cross-platform config.
-    pub fn new(component: F, props: Props, root_contexts: Vec<BoxedContext>) -> Self {
+    pub fn new(props: P) -> Self {
         CrossPlatformConfig {
-            component: new_any_props(component, |_, _| true, props, "root"),
-            root_contexts,
+            props,
+            // root_contexts,
         }
     }
-}
 
-impl<P: AnyProps> CrossPlatformConfig<P> {
-    /// Push a new context into the root component's context.
-    pub fn push_context<T: Any + Clone + 'static>(&mut self, context: T) {
-        self.root_contexts.push(BoxedContext::new(context));
-    }
+    // /// Push a new context into the root component's context.
+    // pub fn push_context<T: Any + Clone + 'static>(&mut self, context: T) {
+    //     self.root_contexts.push(BoxedContext::new(context));
+    // }
 
     /// Build a virtual dom from the config.
     pub fn build_vdom(self) -> VirtualDom {
-        let mut vdom = VirtualDom::new_with_component(self.component);
+        let mut vdom = VirtualDom::new_with_component(self.props);
 
-        for context in self.root_contexts {
-            vdom.insert_boxed_root_context(context);
-        }
+        // for context in self.root_contexts {
+        //     vdom.insert_boxed_root_context(context);
+        // }
 
         vdom
     }

+ 3 - 3
packages/core/src/virtual_dom.rs

@@ -3,7 +3,7 @@
 //! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
 
 use crate::{
-    any_props::{new_any_props, AnyProps},
+    any_props::AnyProps,
     arena::ElementId,
     innerlude::{
         DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount,
@@ -13,7 +13,7 @@ use crate::{
     nodes::{Template, TemplateId},
     runtime::{Runtime, RuntimeGuard},
     scopes::ScopeId,
-    AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task,
+    AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task, VProps,
 };
 use futures_util::{pin_mut, StreamExt};
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -263,7 +263,7 @@ impl VirtualDom {
         root: impl ComponentFunction<P, M>,
         root_props: P,
     ) -> Self {
-        Self::new_with_component(new_any_props(root, |_, _| true, root_props, "root"))
+        Self::new_with_component(VProps::new(root, |_, _| true, root_props, "root"))
     }
 
     /// Create a new virtualdom and build it immediately

+ 6 - 1
packages/dioxus/Cargo.toml

@@ -25,6 +25,8 @@ dioxus-fullstack = { workspace = true, optional = true }
 dioxus-liveview = { workspace = true, optional = true }
 # dioxus-tui = { workspace = true, optional = true }
 
+serde = { version = "1.0.136", optional = true }
+
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 dioxus-hot-reload = { workspace = true, optional = true }
 
@@ -40,11 +42,14 @@ launch = ["dioxus-config-macro"]
 router = ["dioxus-router"]
 
 # Platforms
-fullstack = ["dioxus-fullstack", "dioxus-config-macro/fullstack"]
+fullstack = ["dioxus-fullstack", "dioxus-config-macro/fullstack", "serde"]
 desktop = ["dioxus-desktop", "dioxus-fullstack?/desktop", "dioxus-config-macro/desktop"]
 web = ["dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web"]
 ssr = ["dioxus-fullstack?/ssr", "dioxus-config-macro/ssr"]
 liveview = ["dioxus-desktop", "dioxus-config-macro/liveview"]
+axum = ["dioxus-fullstack?/axum"]
+salvo = ["dioxus-fullstack?/salvo"]
+warp = ["dioxus-fullstack?/warp"]
 # tui = ["dioxus-tui", "dioxus-config-macro/tui"]
 
 [dev-dependencies]

+ 100 - 17
packages/dioxus/src/launch.rs

@@ -13,18 +13,61 @@ pub struct LaunchBuilder<P: AnyProps, Platform: PlatformBuilder<P> = CurrentPlat
     platform_config: Option<<Platform as PlatformBuilder<P>>::Config>,
 }
 
+#[cfg(feature = "fullstack")]
+// Fullstack platform builder
+impl<
+        F: ComponentFunction<Props, M> + Send + Sync,
+        Props: Clone + Send + Sync + 'static,
+        M: Send + Sync + 'static,
+    > LaunchBuilder<VProps<F, Props, M>>
+{
+    /// Create a new builder for your application. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
+    pub fn new(component: F) -> Self
+    where
+        Props: Default,
+    {
+        Self {
+            cross_platform_config: CrossPlatformConfig::new(VProps::new(
+                component,
+                |_, _| true,
+                Default::default(),
+                "root",
+            )),
+            platform_config: None,
+        }
+    }
+
+    /// Create a new builder for your application with some root props. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
+    pub fn new_with_props(component: F, props: Props) -> Self {
+        Self {
+            cross_platform_config: CrossPlatformConfig::new(VProps::new(
+                component,
+                |_, _| true,
+                props,
+                "root",
+            )),
+            platform_config: None,
+        }
+    }
+}
+
+#[cfg(not(feature = "fullstack"))]
 // Default platform builder
-impl<F: ComponentFunction<Props, M>, Props: Clone + Default + 'static, M: 'static>
+impl<F: ComponentFunction<Props, M>, Props: Clone + 'static, M: 'static>
     LaunchBuilder<VProps<F, Props, M>>
 {
     /// Create a new builder for your application. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
-    pub fn new(component: F) -> Self {
+    pub fn new(component: F) -> Self
+    where
+        Props: Default,
+    {
         Self {
-            cross_platform_config: CrossPlatformConfig::new(
+            cross_platform_config: CrossPlatformConfig::new(VProps::new(
                 component,
+                |_, _| true,
                 Default::default(),
-                Default::default(),
-            ),
+                "root",
+            )),
             platform_config: None,
         }
     }
@@ -32,19 +75,24 @@ impl<F: ComponentFunction<Props, M>, Props: Clone + Default + 'static, M: 'stati
     /// Create a new builder for your application with some root props. This will create a launch configuration for the current platform based on the features enabled on the `dioxus` crate.
     pub fn new_with_props(component: F, props: Props) -> Self {
         Self {
-            cross_platform_config: CrossPlatformConfig::new(component, props, Default::default()),
+            cross_platform_config: CrossPlatformConfig::new(VProps::new(
+                component,
+                |_, _| true,
+                props,
+                "root",
+            )),
             platform_config: None,
         }
     }
 }
 
 impl<P: AnyProps, Platform: PlatformBuilder<P>> LaunchBuilder<P, Platform> {
-    /// Inject state into the root component's context.
-    pub fn context(mut self, state: impl Any + Clone + 'static) -> Self {
-        self.cross_platform_config
-            .push_context(BoxedContext::new(state));
-        self
-    }
+    // /// Inject state into the root component's context.
+    // pub fn context(mut self, state: impl Any + Clone + 'static) -> Self {
+    //     self.cross_platform_config
+    //         .push_context(BoxedContext::new(state));
+    //     self
+    // }
 
     /// Provide a platform-specific config to the builder.
     pub fn cfg(
@@ -89,13 +137,37 @@ impl<P: AnyProps> LaunchBuilder<P, dioxus_desktop::DesktopPlatform> {
     }
 }
 
-#[cfg(feature = "desktop")]
+#[cfg(feature = "fullstack")]
+impl<P: AnyProps + Clone + Send + Sync> LaunchBuilder<P, dioxus_fullstack::FullstackPlatform> {
+    /// Launch your fullstack application.
+    pub fn launch_fullstack(self) {
+        dioxus_fullstack::FullstackPlatform::launch(
+            self.cross_platform_config,
+            self.platform_config.unwrap_or_default(),
+        );
+    }
+}
+
+#[cfg(feature = "fullstack")]
+type CurrentPlatform = dioxus_fullstack::FullstackPlatform;
+#[cfg(all(feature = "desktop", not(feature = "fullstack")))]
 type CurrentPlatform = dioxus_desktop::DesktopPlatform;
-#[cfg(all(feature = "web", not(feature = "desktop")))]
+#[cfg(all(feature = "web", not(any(feature = "desktop", feature = "fullstack"))))]
 type CurrentPlatform = dioxus_web::WebPlatform;
-#[cfg(not(any(feature = "desktop", feature = "web")))]
+#[cfg(not(any(feature = "desktop", feature = "web", feature = "fullstack")))]
 type CurrentPlatform = ();
 
+#[cfg(feature = "fullstack")]
+/// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
+pub fn launch<Props, Marker>(component: impl ComponentFunction<Props, Marker> + Send + Sync)
+where
+    Props: Default + Send + Sync + Clone + 'static,
+    Marker: Send + Sync + 'static,
+{
+    LaunchBuilder::new(component).launch()
+}
+
+#[cfg(not(feature = "fullstack"))]
 /// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
 pub fn launch<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
 where
@@ -104,7 +176,7 @@ where
     LaunchBuilder::new(component).launch()
 }
 
-#[cfg(feature = "web")]
+#[cfg(all(feature = "web", not(feature = "fullstack")))]
 /// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options.
 pub fn launch_web<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
 where
@@ -113,7 +185,7 @@ where
     LaunchBuilder::new(component).launch_web()
 }
 
-#[cfg(feature = "desktop")]
+#[cfg(all(feature = "desktop", not(feature = "fullstack")))]
 /// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options.
 pub fn launch_desktop<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
 where
@@ -121,3 +193,14 @@ where
 {
     LaunchBuilder::new(component).launch_desktop()
 }
+
+#[cfg(feature = "fullstack")]
+/// Launch your fullstack application without any additional configuration. See [`LaunchBuilder`] for more options.
+pub fn launch_fullstack<Props, Marker>(
+    component: impl ComponentFunction<Props, Marker> + Send + Sync,
+) where
+    Props: Default + Send + Sync + Clone + 'static,
+    Marker: Send + Sync + 'static,
+{
+    LaunchBuilder::new(component).launch_fullstack()
+}

+ 3 - 0
packages/dioxus/src/lib.rs

@@ -57,6 +57,9 @@ pub mod prelude {
     pub use dioxus_hot_reload::{self, hot_reload_init};
 
     pub use dioxus_core;
+
+    #[cfg(feature = "fullstack")]
+    pub use dioxus_fullstack::prelude::*;
 }
 
 #[cfg(feature = "web")]

+ 3 - 4
packages/fullstack/examples/axum-hello-world/Cargo.toml

@@ -7,8 +7,7 @@ publish = false
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-dioxus = { workspace = true }
-dioxus-fullstack = { workspace = true }
+dioxus = { workspace = true, features = ["fullstack"]}
 serde = "1.0.159"
 simple_logger = "4.2.0"
 tracing-wasm = "0.2.1"
@@ -18,5 +17,5 @@ reqwest = "0.11.18"
 
 [features]
 default = []
-ssr = ["dioxus-fullstack/axum"]
-web = ["dioxus-fullstack/web"]
+ssr = ["dioxus/axum"]
+web = ["dioxus/web"]

+ 5 - 17
packages/fullstack/examples/axum-hello-world/src/main.rs

@@ -7,27 +7,17 @@
 
 #![allow(non_snake_case, unused)]
 use dioxus::prelude::*;
-use dioxus_fullstack::{
-    launch::{self, LaunchBuilder},
-    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 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());
-    let eval = use_eval(cx);
 
     rsx! {
-        div { "Server state: {state}" }
+        // div { "Server state: {state}" }
         h1 { "High-Five counter: {count}" }
         button { onclick: move |_| count += 1, "Up high!" }
         button { onclick: move |_| count -= 1, "Down low!" }
@@ -50,9 +40,7 @@ fn app(cx: Scope<AppProps>) -> Element {
 
 #[server]
 async fn post_server_data(data: String) -> Result<(), ServerFnError> {
-    let axum::extract::Host(host): axum::extract::Host = extract().await?;
     println!("Server received: {}", data);
-    println!("{:?}", host);
 
     Ok(())
 }
@@ -68,5 +56,5 @@ fn main() {
     #[cfg(feature = "ssr")]
     tracing_subscriber::fmt::init();
 
-    LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
+    launch(app);
 }

+ 26 - 11
packages/fullstack/src/adapters/axum_adapter.rs

@@ -63,6 +63,7 @@ use axum::{
     routing::{get, post},
     Router,
 };
+use dioxus_lib::prelude::dioxus_core::{AnyProps, CrossPlatformConfig};
 use server_fn::{Encoding, ServerFunctionRegistry};
 use std::sync::Arc;
 use std::sync::RwLock;
@@ -215,10 +216,11 @@ pub trait DioxusRouterExt<S> {
     ///     todo!()
     /// }
     /// ```
-    fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
+    fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
         self,
         server_fn_route: &'static str,
-        cfg: impl Into<ServeConfig<P>>,
+        cfg: impl Into<ServeConfig>,
+        dioxus_config: CrossPlatformConfig<P>,
     ) -> Self;
 }
 
@@ -313,10 +315,11 @@ where
         self
     }
 
-    fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
+    fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
         self,
         server_fn_route: &'static str,
-        cfg: impl Into<ServeConfig<P>>,
+        cfg: impl Into<ServeConfig>,
+        dioxus_config: CrossPlatformConfig<P>,
     ) -> Self {
         let cfg = cfg.into();
         let ssr_state = SSRState::new(&cfg);
@@ -325,7 +328,7 @@ where
         self.serve_static_assets(cfg.assets_path)
             .connect_hot_reload()
             .register_server_fns(server_fn_route)
-            .fallback(get(render_handler).with_state((cfg, ssr_state)))
+            .fallback(get(render_handler).with_state((cfg, dioxus_config, ssr_state)))
     }
 
     fn connect_hot_reload(self) -> Self {
@@ -416,10 +419,15 @@ fn apply_request_parts_to_response<B>(
 /// }
 /// ```
 pub async fn render_handler_with_context<
-    P: Clone + serde::Serialize + Send + Sync + 'static,
+    P: AnyProps + Clone + Send + Sync + 'static,
     F: FnMut(&mut DioxusServerContext),
 >(
-    State((mut inject_context, cfg, ssr_state)): State<(F, ServeConfig<P>, SSRState)>,
+    State((mut inject_context, cfg, ssr_state, dioxus_config)): State<(
+        F,
+        ServeConfig,
+        SSRState,
+        CrossPlatformConfig<P>,
+    )>,
     request: Request<Body>,
 ) -> impl IntoResponse {
     let (parts, _) = request.into_parts();
@@ -428,7 +436,10 @@ pub async fn render_handler_with_context<
     let mut server_context = DioxusServerContext::new(parts.clone());
     inject_context(&mut server_context);
 
-    match ssr_state.render(url, &cfg, &server_context).await {
+    match ssr_state
+        .render(url, &cfg, dioxus_config, &server_context)
+        .await
+    {
         Ok(rendered) => {
             let crate::render::RenderResponse { html, freshness } = rendered;
             let mut response = axum::response::Html::from(html).into_response();
@@ -445,11 +456,15 @@ pub async fn render_handler_with_context<
 }
 
 /// SSR renderer handler for Axum
-pub async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
-    State((cfg, ssr_state)): State<(ServeConfig<P>, SSRState)>,
+pub async fn render_handler<P: AnyProps + Clone + Send + Sync + 'static>(
+    State((cfg, dioxus_config, ssr_state)): State<(ServeConfig, CrossPlatformConfig<P>, SSRState)>,
     request: Request<Body>,
 ) -> impl IntoResponse {
-    render_handler_with_context(State((|_: &mut _| (), cfg, ssr_state)), request).await
+    render_handler_with_context(
+        State((|_: &mut _| (), cfg, ssr_state, dioxus_config)),
+        request,
+    )
+    .await
 }
 
 fn report_err<E: std::fmt::Display>(e: E) -> Response<BoxBody> {

+ 36 - 14
packages/fullstack/src/launch.rs

@@ -1,17 +1,34 @@
 //! Launch helper macros for fullstack apps
 #![allow(unused)]
 use crate::prelude::*;
-use dioxus_lib::prelude::{dioxus_core::AnyProps, *};
+use dioxus_lib::prelude::{
+    dioxus_core::{AnyProps, CrossPlatformConfig},
+    *,
+};
 
 /// The desktop renderer platform
 pub struct FullstackPlatform;
 
-impl<Props: AnyProps + Send + Sync + 'static> dioxus_core::PlatformBuilder<Props>
+impl<Props: AnyProps + Clone + Send + Sync + 'static> dioxus_core::PlatformBuilder<Props>
     for FullstackPlatform
 {
     type Config = Config;
 
-    fn launch(config: dioxus_core::CrossPlatformConfig<Props>, platform_config: Self::Config) {}
+    fn launch(config: dioxus_core::CrossPlatformConfig<Props>, platform_config: Self::Config) {
+        #[cfg(feature = "ssr")]
+        tokio::runtime::Runtime::new()
+            .unwrap()
+            .block_on(async move {
+                platform_config.launch_server(config).await;
+            });
+        #[cfg(not(feature = "ssr"))]
+        {
+            #[cfg(feature = "web")]
+            platform_config.launch_web(config);
+            #[cfg(feature = "desktop")]
+            platform_config.launch_desktop(config);
+        }
+    }
 }
 
 /// Settings for a fullstack app.
@@ -99,31 +116,33 @@ impl Config {
     }
 
     /// Launch the app.
-    pub fn launch(self) {
+    pub fn launch<P: AnyProps + Clone + Send + Sync>(self, dioxus_config: CrossPlatformConfig<P>) {
         #[cfg(feature = "ssr")]
         tokio::runtime::Runtime::new()
             .unwrap()
             .block_on(async move {
-                self.launch_server().await;
+                self.launch_server(dioxus_config).await;
             });
         #[cfg(not(feature = "ssr"))]
         {
             #[cfg(feature = "web")]
-            self.launch_web();
+            self.launch_web(dioxus_config);
             #[cfg(feature = "desktop")]
-            self.launch_desktop();
+            self.launch_desktop(dioxus_config);
         }
     }
 
     #[cfg(feature = "web")]
     /// Launch the web application
-    pub fn launch_web(self) {
+    pub fn launch_web<P: AnyProps>(self, dioxus_config: CrossPlatformConfig<P>) {
+        use dioxus_lib::prelude::dioxus_core::{CrossPlatformConfig, PlatformBuilder};
+
         #[cfg(not(feature = "ssr"))]
         {
             let cfg = self.web_cfg.hydrate(true);
-            dioxus_web::launch_with_props(
-                self.component,
-                get_root_props_from_document().unwrap(),
+            dioxus_web::WebPlatform::launch(
+                // TODO: this should pull the props from the document
+                dioxus_config,
                 cfg,
             );
         }
@@ -131,14 +150,17 @@ impl Config {
 
     #[cfg(feature = "desktop")]
     /// Launch the web application
-    pub fn launch_desktop(self) {
+    pub fn launch_desktop<P: AnyProps>(self, dioxus_config: CrossPlatformConfig<P>) {
         let cfg = self.desktop_cfg;
         dioxus_desktop::launch_with_props(self.component, self.props, cfg);
     }
 
     #[cfg(feature = "ssr")]
     /// Launch a server application
-    pub async fn launch_server(self) {
+    pub async fn launch_server<P: AnyProps + Send + Sync + Clone>(
+        self,
+        dioxus_config: CrossPlatformConfig<P>,
+    ) {
         let addr = self.addr;
         println!("Listening on {}", addr);
         let cfg = self.server_cfg.build();
@@ -155,7 +177,7 @@ impl Config {
             let router = router
                 .serve_static_assets(cfg.assets_path)
                 .connect_hot_reload()
-                .fallback(get(render_handler).with_state((cfg, ssr_state)));
+                .fallback(get(render_handler).with_state((cfg, dioxus_config, ssr_state)));
             let router = router
                 .layer(
                     ServiceBuilder::new()

+ 2 - 1
packages/fullstack/src/lib.rs

@@ -14,7 +14,8 @@ pub use adapters::*;
 mod hooks;
 #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
 mod hot_reload;
-pub mod launch;
+mod launch;
+pub use launch::*;
 #[cfg(feature = "ssr")]
 mod layer;
 #[cfg(feature = "ssr")]

+ 20 - 23
packages/fullstack/src/render.rs

@@ -1,5 +1,6 @@
 //! A shared pool of renderers for efficient server side rendering.
-
+use crate::render::dioxus_core::AnyProps;
+use crate::render::dioxus_core::CrossPlatformConfig;
 use crate::render::dioxus_core::NoOpMutations;
 use crate::server_context::SERVER_CONTEXT;
 use dioxus_lib::prelude::VirtualDom;
@@ -21,15 +22,15 @@ enum SsrRendererPool {
 }
 
 impl SsrRendererPool {
-    async fn render_to<P: Clone + Serialize + Send + Sync + 'static>(
+    async fn render_to<P: AnyProps + Clone + Send + Sync + 'static>(
         &self,
-        cfg: &ServeConfig<P>,
+        cfg: &ServeConfig,
         route: String,
-        component: Component<P>,
-        props: P,
+        dioxus_config: CrossPlatformConfig<P>,
         server_context: &DioxusServerContext,
     ) -> Result<(RenderFreshness, String), dioxus_ssr::incremental::IncrementalRendererError> {
         let wrapper = FullstackRenderer {
+            serialized_props: None,
             cfg: cfg.clone(),
             server_context: server_context.clone(),
         };
@@ -44,7 +45,7 @@ impl SsrRendererPool {
                     tokio::runtime::Runtime::new()
                         .expect("couldn't spawn runtime")
                         .block_on(async move {
-                            let mut vdom = VirtualDom::new_with_props(component, props);
+                            let mut vdom = dioxus_config.build_vdom();
                             vdom.in_runtime(|| {
                                 // Make sure the evaluator is initialized
                                 dioxus_ssr::eval::init_eval();
@@ -111,8 +112,7 @@ impl SsrRendererPool {
                             match renderer
                                 .render(
                                     route,
-                                    component,
-                                    props,
+                                    dioxus_config,
                                     &mut *to,
                                     |vdom| {
                                         Box::pin(async move {
@@ -169,7 +169,7 @@ pub struct SSRState {
 
 impl SSRState {
     /// Create a new [`SSRState`].
-    pub fn new<P: Clone>(cfg: &ServeConfig<P>) -> Self {
+    pub fn new(cfg: &ServeConfig) -> Self {
         if cfg.incremental.is_some() {
             return Self {
                 renderers: Arc::new(SsrRendererPool::Incremental(RwLock::new(vec![
@@ -192,13 +192,12 @@ impl SSRState {
     }
 
     /// Render the application to HTML.
-    pub fn render<'a, P: 'static + Clone + serde::Serialize + Send + Sync>(
+    pub fn render<'a, P: AnyProps + Clone + Send + Sync>(
         &'a self,
         route: String,
-        cfg: &'a ServeConfig<P>,
+        cfg: &'a ServeConfig,
+        dioxus_config: CrossPlatformConfig<P>,
         server_context: &'a DioxusServerContext,
-        app: Component<P>,
-        props: P,
     ) -> impl std::future::Future<
         Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
     > + Send
@@ -208,7 +207,7 @@ impl SSRState {
 
             let (freshness, html) = self
                 .renderers
-                .render_to(cfg, route, app, props, server_context)
+                .render_to(cfg, route, dioxus_config, server_context)
                 .await?;
 
             Ok(RenderResponse { html, freshness })
@@ -216,16 +215,13 @@ impl SSRState {
     }
 }
 
-struct FullstackRenderer<P: Clone + Send + Sync + 'static> {
-    component: Component<P>,
-    props: P,
+struct FullstackRenderer {
+    serialized_props: Option<String>,
     cfg: ServeConfig,
     server_context: DioxusServerContext,
 }
 
-impl<P: Clone + Serialize + Send + Sync + 'static> dioxus_ssr::incremental::WrapBody
-    for FullstackRenderer<P>
-{
+impl dioxus_ssr::incremental::WrapBody for FullstackRenderer {
     fn render_before_body<R: std::io::Write>(
         &self,
         to: &mut R,
@@ -242,9 +238,10 @@ impl<P: Clone + Serialize + Send + Sync + 'static> dioxus_ssr::incremental::Wrap
         to: &mut R,
     ) -> Result<(), dioxus_ssr::incremental::IncrementalRendererError> {
         // serialize the props
-        crate::html_storage::serialize::encode_props_in_element(&self.cfg.props, to).map_err(
-            |err| dioxus_ssr::incremental::IncrementalRendererError::Other(Box::new(err)),
-        )?;
+        // TODO: restore props serialization
+        // crate::html_storage::serialize::encode_props_in_element(&self.cfg.props, to).map_err(
+        //     |err| dioxus_ssr::incremental::IncrementalRendererError::Other(Box::new(err)),
+        // )?;
         // serialize the server state
         crate::html_storage::serialize::encode_in_element(
             &*self.server_context.html_data().map_err(|_| {

+ 3 - 3
packages/server-macro/src/lib.rs

@@ -98,9 +98,9 @@ pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
         }
     };
 
-    let server_fn_path: syn::Path = syn::parse_quote!(::dioxus_fullstack::prelude::server_fn);
+    let server_fn_path: syn::Path = syn::parse_quote!(::dioxus::fullstack::prelude::server_fn);
     let trait_obj_wrapper: syn::Type =
-        syn::parse_quote!(::dioxus_fullstack::prelude::ServerFnTraitObj);
+        syn::parse_quote!(::dioxus::fullstack::prelude::ServerFnTraitObj);
     let mut args: ServerFnArgs = match syn::parse(args) {
         Ok(args) => args,
         Err(e) => return e.to_compile_error().into(),
@@ -125,7 +125,7 @@ pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
             #tokens
             #[cfg(feature = "ssr")]
             #server_fn_path::inventory::submit! {
-                ::dioxus_fullstack::prelude::ServerFnMiddleware {
+                ::dioxus::fullstack::prelude::ServerFnMiddleware {
                     prefix: #struct_name::PREFIX,
                     url: #struct_name::URL,
                     middleware: || vec![

+ 7 - 9
packages/ssr/src/incremental.rs

@@ -3,7 +3,7 @@
 #![allow(non_snake_case)]
 
 use crate::fs_cache::ValidCachedPath;
-use dioxus_core::{Element, VirtualDom};
+use dioxus_core::{AnyProps, CrossPlatformConfig, VirtualDom};
 use rustc_hash::FxHasher;
 use std::{
     future::Future,
@@ -69,18 +69,17 @@ impl IncrementalRenderer {
         self.invalidate_after.is_some()
     }
 
-    async fn render_and_cache<'a, P: Clone + 'static, R: WrapBody + Send + Sync>(
+    async fn render_and_cache<'a, P: AnyProps + 'static, R: WrapBody + Send + Sync>(
         &'a mut self,
         route: String,
-        comp: fn(P) -> Element,
-        props: P,
+        dioxus_config: CrossPlatformConfig<P>,
         output: &'a mut (impl AsyncWrite + Unpin + Send),
         rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
         renderer: &'a R,
     ) -> Result<RenderFreshness, IncrementalRendererError> {
         let mut html_buffer = WriteBuffer { buffer: Vec::new() };
         {
-            let mut vdom = VirtualDom::new_with_props(comp, props);
+            let mut vdom = dioxus_config.build_vdom();
             vdom.in_runtime(crate::eval::init_eval);
             rebuild_with(&mut vdom).await;
 
@@ -168,11 +167,10 @@ impl IncrementalRenderer {
     }
 
     /// Render a route or get it from cache.
-    pub async fn render<P: Clone + 'static, R: WrapBody + Send + Sync>(
+    pub async fn render<P: AnyProps, R: WrapBody + Send + Sync>(
         &mut self,
         route: String,
-        component: fn(P) -> Element,
-        props: P,
+        dioxus_config: CrossPlatformConfig<P>,
         output: &mut (impl AsyncWrite + Unpin + std::marker::Send),
         rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
         renderer: &R,
@@ -183,7 +181,7 @@ impl IncrementalRenderer {
         } else {
             // if not, create it
             let freshness = self
-                .render_and_cache(route, component, props, output, rebuild_with, renderer)
+                .render_and_cache(route, dioxus_config, output, rebuild_with, renderer)
                 .await?;
             tracing::trace!("cache miss");
             Ok(freshness)

+ 6 - 3
packages/web/src/lib.rs

@@ -60,7 +60,7 @@ use std::rc::Rc;
 pub use crate::cfg::Config;
 #[cfg(feature = "file_engine")]
 pub use crate::file_engine::WebFileEngineExt;
-use dioxus_core::CrossPlatformConfig;
+use dioxus_core::{AnyProps, CrossPlatformConfig};
 use futures_util::{
     future::{select, Either},
     pin_mut, FutureExt, StreamExt,
@@ -99,7 +99,10 @@ mod rehydrate;
 ///     wasm_bindgen_futures::spawn_local(app_fut);
 /// }
 /// ```
-pub async fn run_with_props(dioxus_config: CrossPlatformConfig, web_config: Config) {
+pub async fn run_with_props<P: AnyProps>(
+    dioxus_config: CrossPlatformConfig<P>,
+    web_config: Config,
+) {
     tracing::info!("Starting up");
 
     let mut dom = dioxus_config.build_vdom();
@@ -123,7 +126,7 @@ pub async fn run_with_props(dioxus_config: CrossPlatformConfig, web_config: Conf
     let (tx, mut rx) = futures_channel::mpsc::unbounded();
 
     #[cfg(feature = "hydrate")]
-    let should_hydrate = cfg.hydrate;
+    let should_hydrate = web_config.hydrate;
     #[cfg(not(feature = "hydrate"))]
     let should_hydrate = false;
 

+ 2 - 2
packages/web/src/platform.rs

@@ -5,10 +5,10 @@ use crate::Config;
 /// The web renderer platform
 pub struct WebPlatform;
 
-impl PlatformBuilder for WebPlatform {
+impl<P: AnyProps> PlatformBuilder<P> for WebPlatform {
     type Config = Config;
 
-    fn launch(config: CrossPlatformConfig, platform_config: Self::Config) {
+    fn launch(config: CrossPlatformConfig<P>, platform_config: Self::Config) {
         wasm_bindgen_futures::spawn_local(async move {
             crate::run_with_props(config, platform_config).await;
         });