mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
make fullstack hello world compile
This commit is contained in:
parent
499e81fa82
commit
ae3e167cfe
19 changed files with 288 additions and 155 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -787,7 +787,6 @@ name = "axum-hello-world"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-fullstack",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
|
@ -2363,6 +2362,7 @@ dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
@ -7,7 +7,7 @@ use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn server(input: TokenStream) -> TokenStream {
|
pub fn server_only(input: TokenStream) -> TokenStream {
|
||||||
if cfg!(any(feature = "ssr", feature = "liveview")) {
|
if cfg!(any(feature = "ssr", feature = "liveview")) {
|
||||||
let input = TokenStream2::from(input);
|
let input = TokenStream2::from(input);
|
||||||
quote! {
|
quote! {
|
||||||
|
|
|
@ -5,14 +5,40 @@ pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
|
||||||
|
|
||||||
/// A trait for a component that can be rendered.
|
/// A trait for a component that can be rendered.
|
||||||
pub trait AnyProps: 'static {
|
pub trait AnyProps: 'static {
|
||||||
|
/// Render the component with the internal props.
|
||||||
fn render(&self) -> RenderReturn;
|
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;
|
fn memoize(&self, other: &dyn Any) -> bool;
|
||||||
|
/// Get the props as a type erased `dyn Any`.
|
||||||
fn props(&self) -> &dyn Any;
|
fn props(&self) -> &dyn Any;
|
||||||
|
/// Duplicate this component into a new boxed component.
|
||||||
fn duplicate(&self) -> BoxedAnyProps;
|
fn duplicate(&self) -> BoxedAnyProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new boxed props object.
|
/// A component along with the props the component uses to render.
|
||||||
pub(crate) fn new_any_props<F: ComponentFunction<P, M>, P: Clone + 'static, M: 'static>(
|
pub struct VProps<F: ComponentFunction<P, M>, P, M> {
|
||||||
|
render_fn: F,
|
||||||
|
memo: fn(&P, &P) -> bool,
|
||||||
|
props: P,
|
||||||
|
name: &'static str,
|
||||||
|
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,
|
render_fn: F,
|
||||||
memo: fn(&P, &P) -> bool,
|
memo: fn(&P, &P) -> bool,
|
||||||
props: P,
|
props: P,
|
||||||
|
@ -27,13 +53,10 @@ pub(crate) fn new_any_props<F: ComponentFunction<P, M>, P: Clone + 'static, M: '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A component along with the props the component uses to render.
|
/// Get the current props of the VProps object
|
||||||
pub struct VProps<F: ComponentFunction<P, M>, P, M> {
|
pub fn props(&self) -> &P {
|
||||||
render_fn: F,
|
&self.props
|
||||||
memo: fn(&P, &P) -> bool,
|
}
|
||||||
props: P,
|
|
||||||
name: &'static str,
|
|
||||||
phantom: std::marker::PhantomData<M>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> AnyProps
|
impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> AnyProps
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use crate::{
|
use crate::{any_props::BoxedAnyProps, innerlude::ScopeState, VProps};
|
||||||
any_props::{new_any_props, BoxedAnyProps},
|
|
||||||
innerlude::ScopeState,
|
|
||||||
};
|
|
||||||
use crate::{arena::ElementId, Element, Event};
|
use crate::{arena::ElementId, Element, Event};
|
||||||
use crate::{
|
use crate::{
|
||||||
innerlude::{ElementRef, EventHandler, MountId},
|
innerlude::{ElementRef, EventHandler, MountId},
|
||||||
|
@ -529,7 +526,7 @@ impl VComponent {
|
||||||
P: Properties + 'static,
|
P: Properties + 'static,
|
||||||
{
|
{
|
||||||
let render_fn = component.id();
|
let render_fn = component.id();
|
||||||
let props = Box::new(new_any_props(
|
let props = Box::new(VProps::new(
|
||||||
component,
|
component,
|
||||||
<P as Properties>::memoize,
|
<P as Properties>::memoize,
|
||||||
props,
|
props,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any_props::{new_any_props, AnyProps, VProps},
|
any_props::{AnyProps, VProps},
|
||||||
properties::ComponentFunction,
|
properties::ComponentFunction,
|
||||||
VirtualDom,
|
VirtualDom,
|
||||||
};
|
};
|
||||||
|
@ -44,38 +44,37 @@ impl<T: Any + Clone> ClonableAny for T {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The platform-independent part of the config needed to launch an application.
|
/// The platform-independent part of the config needed to launch an application.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct CrossPlatformConfig<P: AnyProps> {
|
pub struct CrossPlatformConfig<P: AnyProps> {
|
||||||
/// The root component function.
|
/// The root component function.
|
||||||
component: P,
|
props: P,
|
||||||
/// The contexts to provide to the root component.
|
// /// The contexts to provide to the root component.
|
||||||
root_contexts: Vec<BoxedContext>,
|
// root_contexts: Vec<BoxedContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: ComponentFunction<Props, M>, Props: Clone + 'static, M: 'static>
|
impl<P: AnyProps> CrossPlatformConfig<P> {}
|
||||||
CrossPlatformConfig<VProps<F, Props, M>>
|
|
||||||
{
|
|
||||||
/// Create a new cross-platform config.
|
|
||||||
pub fn new(component: F, props: Props, root_contexts: Vec<BoxedContext>) -> Self {
|
|
||||||
CrossPlatformConfig {
|
|
||||||
component: new_any_props(component, |_, _| true, props, "root"),
|
|
||||||
root_contexts,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P: AnyProps> CrossPlatformConfig<P> {
|
impl<P: AnyProps> CrossPlatformConfig<P> {
|
||||||
/// Push a new context into the root component's context.
|
/// Create a new cross-platform config.
|
||||||
pub fn push_context<T: Any + Clone + 'static>(&mut self, context: T) {
|
pub fn new(props: P) -> Self {
|
||||||
self.root_contexts.push(BoxedContext::new(context));
|
CrossPlatformConfig {
|
||||||
|
props,
|
||||||
|
// root_contexts,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// 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.
|
/// Build a virtual dom from the config.
|
||||||
pub fn build_vdom(self) -> VirtualDom {
|
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 {
|
// for context in self.root_contexts {
|
||||||
vdom.insert_boxed_root_context(context);
|
// vdom.insert_boxed_root_context(context);
|
||||||
}
|
// }
|
||||||
|
|
||||||
vdom
|
vdom
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
|
//! This module provides the primary mechanics to create a hook-based, concurrent VDOM for Rust.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
any_props::{new_any_props, AnyProps},
|
any_props::AnyProps,
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
innerlude::{
|
innerlude::{
|
||||||
DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount,
|
DirtyScope, ElementRef, ErrorBoundary, NoOpMutations, SchedulerMsg, ScopeState, VNodeMount,
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
nodes::{Template, TemplateId},
|
nodes::{Template, TemplateId},
|
||||||
runtime::{Runtime, RuntimeGuard},
|
runtime::{Runtime, RuntimeGuard},
|
||||||
scopes::ScopeId,
|
scopes::ScopeId,
|
||||||
AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task,
|
AttributeValue, BoxedContext, ComponentFunction, Element, Event, Mutations, Task, VProps,
|
||||||
};
|
};
|
||||||
use futures_util::{pin_mut, StreamExt};
|
use futures_util::{pin_mut, StreamExt};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
@ -263,7 +263,7 @@ impl VirtualDom {
|
||||||
root: impl ComponentFunction<P, M>,
|
root: impl ComponentFunction<P, M>,
|
||||||
root_props: P,
|
root_props: P,
|
||||||
) -> Self {
|
) -> 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
|
/// Create a new virtualdom and build it immediately
|
||||||
|
|
|
@ -25,6 +25,8 @@ dioxus-fullstack = { workspace = true, optional = true }
|
||||||
dioxus-liveview = { workspace = true, optional = true }
|
dioxus-liveview = { workspace = true, optional = true }
|
||||||
# dioxus-tui = { workspace = true, optional = true }
|
# dioxus-tui = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
serde = { version = "1.0.136", optional = true }
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
dioxus-hot-reload = { workspace = true, optional = true }
|
dioxus-hot-reload = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
@ -40,11 +42,14 @@ launch = ["dioxus-config-macro"]
|
||||||
router = ["dioxus-router"]
|
router = ["dioxus-router"]
|
||||||
|
|
||||||
# Platforms
|
# 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"]
|
desktop = ["dioxus-desktop", "dioxus-fullstack?/desktop", "dioxus-config-macro/desktop"]
|
||||||
web = ["dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web"]
|
web = ["dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web"]
|
||||||
ssr = ["dioxus-fullstack?/ssr", "dioxus-config-macro/ssr"]
|
ssr = ["dioxus-fullstack?/ssr", "dioxus-config-macro/ssr"]
|
||||||
liveview = ["dioxus-desktop", "dioxus-config-macro/liveview"]
|
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"]
|
# tui = ["dioxus-tui", "dioxus-config-macro/tui"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -13,18 +13,26 @@ pub struct LaunchBuilder<P: AnyProps, Platform: PlatformBuilder<P> = CurrentPlat
|
||||||
platform_config: Option<<Platform as PlatformBuilder<P>>::Config>,
|
platform_config: Option<<Platform as PlatformBuilder<P>>::Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default platform builder
|
#[cfg(feature = "fullstack")]
|
||||||
impl<F: ComponentFunction<Props, M>, Props: Clone + Default + 'static, M: 'static>
|
// Fullstack platform builder
|
||||||
LaunchBuilder<VProps<F, Props, M>>
|
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.
|
/// 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 {
|
Self {
|
||||||
cross_platform_config: CrossPlatformConfig::new(
|
cross_platform_config: CrossPlatformConfig::new(VProps::new(
|
||||||
component,
|
component,
|
||||||
|
|_, _| true,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
Default::default(),
|
"root",
|
||||||
),
|
)),
|
||||||
platform_config: None,
|
platform_config: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,19 +40,59 @@ 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.
|
/// 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 {
|
pub fn new_with_props(component: F, props: Props) -> Self {
|
||||||
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "fullstack"))]
|
||||||
|
// Default platform builder
|
||||||
|
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
|
||||||
|
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,
|
platform_config: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: AnyProps, Platform: PlatformBuilder<P>> LaunchBuilder<P, Platform> {
|
impl<P: AnyProps, Platform: PlatformBuilder<P>> LaunchBuilder<P, Platform> {
|
||||||
/// Inject state into the root component's context.
|
// /// Inject state into the root component's context.
|
||||||
pub fn context(mut self, state: impl Any + Clone + 'static) -> Self {
|
// pub fn context(mut self, state: impl Any + Clone + 'static) -> Self {
|
||||||
self.cross_platform_config
|
// self.cross_platform_config
|
||||||
.push_context(BoxedContext::new(state));
|
// .push_context(BoxedContext::new(state));
|
||||||
self
|
// self
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Provide a platform-specific config to the builder.
|
/// Provide a platform-specific config to the builder.
|
||||||
pub fn cfg(
|
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;
|
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;
|
type CurrentPlatform = dioxus_web::WebPlatform;
|
||||||
#[cfg(not(any(feature = "desktop", feature = "web")))]
|
#[cfg(not(any(feature = "desktop", feature = "web", feature = "fullstack")))]
|
||||||
type CurrentPlatform = ();
|
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.
|
/// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||||
pub fn launch<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
pub fn launch<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
||||||
where
|
where
|
||||||
|
@ -104,7 +176,7 @@ where
|
||||||
LaunchBuilder::new(component).launch()
|
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.
|
/// 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>)
|
pub fn launch_web<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
||||||
where
|
where
|
||||||
|
@ -113,7 +185,7 @@ where
|
||||||
LaunchBuilder::new(component).launch_web()
|
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.
|
/// 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>)
|
pub fn launch_desktop<Props, Marker: 'static>(component: impl ComponentFunction<Props, Marker>)
|
||||||
where
|
where
|
||||||
|
@ -121,3 +193,14 @@ where
|
||||||
{
|
{
|
||||||
LaunchBuilder::new(component).launch_desktop()
|
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()
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ pub mod prelude {
|
||||||
pub use dioxus_hot_reload::{self, hot_reload_init};
|
pub use dioxus_hot_reload::{self, hot_reload_init};
|
||||||
|
|
||||||
pub use dioxus_core;
|
pub use dioxus_core;
|
||||||
|
|
||||||
|
#[cfg(feature = "fullstack")]
|
||||||
|
pub use dioxus_fullstack::prelude::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "web")]
|
#[cfg(feature = "web")]
|
||||||
|
|
|
@ -7,8 +7,7 @@ publish = false
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { workspace = true }
|
dioxus = { workspace = true, features = ["fullstack"]}
|
||||||
dioxus-fullstack = { workspace = true }
|
|
||||||
serde = "1.0.159"
|
serde = "1.0.159"
|
||||||
simple_logger = "4.2.0"
|
simple_logger = "4.2.0"
|
||||||
tracing-wasm = "0.2.1"
|
tracing-wasm = "0.2.1"
|
||||||
|
@ -18,5 +17,5 @@ reqwest = "0.11.18"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
ssr = ["dioxus-fullstack/axum"]
|
ssr = ["dioxus/axum"]
|
||||||
web = ["dioxus-fullstack/web"]
|
web = ["dioxus/web"]
|
||||||
|
|
|
@ -7,27 +7,17 @@
|
||||||
|
|
||||||
#![allow(non_snake_case, unused)]
|
#![allow(non_snake_case, unused)]
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_fullstack::{
|
|
||||||
launch::{self, LaunchBuilder},
|
|
||||||
prelude::*,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Props, PartialEq, Debug, Default, Serialize, Deserialize, Clone)]
|
fn app() -> Element {
|
||||||
struct AppProps {
|
// let state = use_server_future(|| async move { get_server_data().await.unwrap() })?;
|
||||||
count: i32,
|
// let state = state.value();
|
||||||
}
|
|
||||||
|
|
||||||
fn app(cx: Scope<AppProps>) -> Element {
|
|
||||||
let state =
|
|
||||||
use_server_future((), |()| async move { get_server_data().await.unwrap() })?.value();
|
|
||||||
|
|
||||||
let mut count = use_signal(|| 0);
|
let mut count = use_signal(|| 0);
|
||||||
let text = use_signal(|| "...".to_string());
|
let text = use_signal(|| "...".to_string());
|
||||||
let eval = use_eval(cx);
|
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div { "Server state: {state}" }
|
// div { "Server state: {state}" }
|
||||||
h1 { "High-Five counter: {count}" }
|
h1 { "High-Five counter: {count}" }
|
||||||
button { onclick: move |_| count += 1, "Up high!" }
|
button { onclick: move |_| count += 1, "Up high!" }
|
||||||
button { onclick: move |_| count -= 1, "Down low!" }
|
button { onclick: move |_| count -= 1, "Down low!" }
|
||||||
|
@ -50,9 +40,7 @@ fn app(cx: Scope<AppProps>) -> Element {
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
async fn post_server_data(data: String) -> Result<(), ServerFnError> {
|
async fn post_server_data(data: String) -> Result<(), ServerFnError> {
|
||||||
let axum::extract::Host(host): axum::extract::Host = extract().await?;
|
|
||||||
println!("Server received: {}", data);
|
println!("Server received: {}", data);
|
||||||
println!("{:?}", host);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -68,5 +56,5 @@ fn main() {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
LaunchBuilder::new_with_props(app, AppProps { count: 0 }).launch()
|
launch(app);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ use axum::{
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
use dioxus_lib::prelude::dioxus_core::{AnyProps, CrossPlatformConfig};
|
||||||
use server_fn::{Encoding, ServerFunctionRegistry};
|
use server_fn::{Encoding, ServerFunctionRegistry};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
@ -215,10 +216,11 @@ pub trait DioxusRouterExt<S> {
|
||||||
/// todo!()
|
/// todo!()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||||
self,
|
self,
|
||||||
server_fn_route: &'static str,
|
server_fn_route: &'static str,
|
||||||
cfg: impl Into<ServeConfig<P>>,
|
cfg: impl Into<ServeConfig>,
|
||||||
|
dioxus_config: CrossPlatformConfig<P>,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,10 +315,11 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serve_dioxus_application<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||||
self,
|
self,
|
||||||
server_fn_route: &'static str,
|
server_fn_route: &'static str,
|
||||||
cfg: impl Into<ServeConfig<P>>,
|
cfg: impl Into<ServeConfig>,
|
||||||
|
dioxus_config: CrossPlatformConfig<P>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cfg = cfg.into();
|
let cfg = cfg.into();
|
||||||
let ssr_state = SSRState::new(&cfg);
|
let ssr_state = SSRState::new(&cfg);
|
||||||
|
@ -325,7 +328,7 @@ where
|
||||||
self.serve_static_assets(cfg.assets_path)
|
self.serve_static_assets(cfg.assets_path)
|
||||||
.connect_hot_reload()
|
.connect_hot_reload()
|
||||||
.register_server_fns(server_fn_route)
|
.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 {
|
fn connect_hot_reload(self) -> Self {
|
||||||
|
@ -416,10 +419,15 @@ fn apply_request_parts_to_response<B>(
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn render_handler_with_context<
|
pub async fn render_handler_with_context<
|
||||||
P: Clone + serde::Serialize + Send + Sync + 'static,
|
P: AnyProps + Clone + Send + Sync + 'static,
|
||||||
F: FnMut(&mut DioxusServerContext),
|
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>,
|
request: Request<Body>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let (parts, _) = request.into_parts();
|
let (parts, _) = request.into_parts();
|
||||||
|
@ -428,7 +436,10 @@ pub async fn render_handler_with_context<
|
||||||
let mut server_context = DioxusServerContext::new(parts.clone());
|
let mut server_context = DioxusServerContext::new(parts.clone());
|
||||||
inject_context(&mut server_context);
|
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) => {
|
Ok(rendered) => {
|
||||||
let crate::render::RenderResponse { html, freshness } = rendered;
|
let crate::render::RenderResponse { html, freshness } = rendered;
|
||||||
let mut response = axum::response::Html::from(html).into_response();
|
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
|
/// SSR renderer handler for Axum
|
||||||
pub async fn render_handler<P: Clone + serde::Serialize + Send + Sync + 'static>(
|
pub async fn render_handler<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||||
State((cfg, ssr_state)): State<(ServeConfig<P>, SSRState)>,
|
State((cfg, dioxus_config, ssr_state)): State<(ServeConfig, CrossPlatformConfig<P>, SSRState)>,
|
||||||
request: Request<Body>,
|
request: Request<Body>,
|
||||||
) -> impl IntoResponse {
|
) -> 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> {
|
fn report_err<E: std::fmt::Display>(e: E) -> Response<BoxBody> {
|
||||||
|
|
|
@ -1,17 +1,34 @@
|
||||||
//! Launch helper macros for fullstack apps
|
//! Launch helper macros for fullstack apps
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use dioxus_lib::prelude::{dioxus_core::AnyProps, *};
|
use dioxus_lib::prelude::{
|
||||||
|
dioxus_core::{AnyProps, CrossPlatformConfig},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
/// The desktop renderer platform
|
/// The desktop renderer platform
|
||||||
pub struct FullstackPlatform;
|
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
|
for FullstackPlatform
|
||||||
{
|
{
|
||||||
type Config = Config;
|
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.
|
/// Settings for a fullstack app.
|
||||||
|
@ -99,31 +116,33 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Launch the app.
|
/// Launch the app.
|
||||||
pub fn launch(self) {
|
pub fn launch<P: AnyProps + Clone + Send + Sync>(self, dioxus_config: CrossPlatformConfig<P>) {
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
tokio::runtime::Runtime::new()
|
tokio::runtime::Runtime::new()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
self.launch_server().await;
|
self.launch_server(dioxus_config).await;
|
||||||
});
|
});
|
||||||
#[cfg(not(feature = "ssr"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
{
|
{
|
||||||
#[cfg(feature = "web")]
|
#[cfg(feature = "web")]
|
||||||
self.launch_web();
|
self.launch_web(dioxus_config);
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
self.launch_desktop();
|
self.launch_desktop(dioxus_config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "web")]
|
#[cfg(feature = "web")]
|
||||||
/// Launch the web application
|
/// 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"))]
|
#[cfg(not(feature = "ssr"))]
|
||||||
{
|
{
|
||||||
let cfg = self.web_cfg.hydrate(true);
|
let cfg = self.web_cfg.hydrate(true);
|
||||||
dioxus_web::launch_with_props(
|
dioxus_web::WebPlatform::launch(
|
||||||
self.component,
|
// TODO: this should pull the props from the document
|
||||||
get_root_props_from_document().unwrap(),
|
dioxus_config,
|
||||||
cfg,
|
cfg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -131,14 +150,17 @@ impl Config {
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
#[cfg(feature = "desktop")]
|
||||||
/// Launch the web application
|
/// 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;
|
let cfg = self.desktop_cfg;
|
||||||
dioxus_desktop::launch_with_props(self.component, self.props, cfg);
|
dioxus_desktop::launch_with_props(self.component, self.props, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
/// Launch a server application
|
/// 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;
|
let addr = self.addr;
|
||||||
println!("Listening on {}", addr);
|
println!("Listening on {}", addr);
|
||||||
let cfg = self.server_cfg.build();
|
let cfg = self.server_cfg.build();
|
||||||
|
@ -155,7 +177,7 @@ impl Config {
|
||||||
let router = router
|
let router = router
|
||||||
.serve_static_assets(cfg.assets_path)
|
.serve_static_assets(cfg.assets_path)
|
||||||
.connect_hot_reload()
|
.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
|
let router = router
|
||||||
.layer(
|
.layer(
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
|
|
|
@ -14,7 +14,8 @@ pub use adapters::*;
|
||||||
mod hooks;
|
mod hooks;
|
||||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
|
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
|
||||||
mod hot_reload;
|
mod hot_reload;
|
||||||
pub mod launch;
|
mod launch;
|
||||||
|
pub use launch::*;
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
mod layer;
|
mod layer;
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! A shared pool of renderers for efficient server side rendering.
|
//! 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::render::dioxus_core::NoOpMutations;
|
||||||
use crate::server_context::SERVER_CONTEXT;
|
use crate::server_context::SERVER_CONTEXT;
|
||||||
use dioxus_lib::prelude::VirtualDom;
|
use dioxus_lib::prelude::VirtualDom;
|
||||||
|
@ -21,15 +22,15 @@ enum SsrRendererPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SsrRendererPool {
|
impl SsrRendererPool {
|
||||||
async fn render_to<P: Clone + Serialize + Send + Sync + 'static>(
|
async fn render_to<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||||
&self,
|
&self,
|
||||||
cfg: &ServeConfig<P>,
|
cfg: &ServeConfig,
|
||||||
route: String,
|
route: String,
|
||||||
component: Component<P>,
|
dioxus_config: CrossPlatformConfig<P>,
|
||||||
props: P,
|
|
||||||
server_context: &DioxusServerContext,
|
server_context: &DioxusServerContext,
|
||||||
) -> Result<(RenderFreshness, String), dioxus_ssr::incremental::IncrementalRendererError> {
|
) -> Result<(RenderFreshness, String), dioxus_ssr::incremental::IncrementalRendererError> {
|
||||||
let wrapper = FullstackRenderer {
|
let wrapper = FullstackRenderer {
|
||||||
|
serialized_props: None,
|
||||||
cfg: cfg.clone(),
|
cfg: cfg.clone(),
|
||||||
server_context: server_context.clone(),
|
server_context: server_context.clone(),
|
||||||
};
|
};
|
||||||
|
@ -44,7 +45,7 @@ impl SsrRendererPool {
|
||||||
tokio::runtime::Runtime::new()
|
tokio::runtime::Runtime::new()
|
||||||
.expect("couldn't spawn runtime")
|
.expect("couldn't spawn runtime")
|
||||||
.block_on(async move {
|
.block_on(async move {
|
||||||
let mut vdom = VirtualDom::new_with_props(component, props);
|
let mut vdom = dioxus_config.build_vdom();
|
||||||
vdom.in_runtime(|| {
|
vdom.in_runtime(|| {
|
||||||
// Make sure the evaluator is initialized
|
// Make sure the evaluator is initialized
|
||||||
dioxus_ssr::eval::init_eval();
|
dioxus_ssr::eval::init_eval();
|
||||||
|
@ -111,8 +112,7 @@ impl SsrRendererPool {
|
||||||
match renderer
|
match renderer
|
||||||
.render(
|
.render(
|
||||||
route,
|
route,
|
||||||
component,
|
dioxus_config,
|
||||||
props,
|
|
||||||
&mut *to,
|
&mut *to,
|
||||||
|vdom| {
|
|vdom| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
|
@ -169,7 +169,7 @@ pub struct SSRState {
|
||||||
|
|
||||||
impl SSRState {
|
impl SSRState {
|
||||||
/// Create a new [`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() {
|
if cfg.incremental.is_some() {
|
||||||
return Self {
|
return Self {
|
||||||
renderers: Arc::new(SsrRendererPool::Incremental(RwLock::new(vec![
|
renderers: Arc::new(SsrRendererPool::Incremental(RwLock::new(vec![
|
||||||
|
@ -192,13 +192,12 @@ impl SSRState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the application to HTML.
|
/// 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,
|
&'a self,
|
||||||
route: String,
|
route: String,
|
||||||
cfg: &'a ServeConfig<P>,
|
cfg: &'a ServeConfig,
|
||||||
|
dioxus_config: CrossPlatformConfig<P>,
|
||||||
server_context: &'a DioxusServerContext,
|
server_context: &'a DioxusServerContext,
|
||||||
app: Component<P>,
|
|
||||||
props: P,
|
|
||||||
) -> impl std::future::Future<
|
) -> impl std::future::Future<
|
||||||
Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
|
Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
|
||||||
> + Send
|
> + Send
|
||||||
|
@ -208,7 +207,7 @@ impl SSRState {
|
||||||
|
|
||||||
let (freshness, html) = self
|
let (freshness, html) = self
|
||||||
.renderers
|
.renderers
|
||||||
.render_to(cfg, route, app, props, server_context)
|
.render_to(cfg, route, dioxus_config, server_context)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(RenderResponse { html, freshness })
|
Ok(RenderResponse { html, freshness })
|
||||||
|
@ -216,16 +215,13 @@ impl SSRState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FullstackRenderer<P: Clone + Send + Sync + 'static> {
|
struct FullstackRenderer {
|
||||||
component: Component<P>,
|
serialized_props: Option<String>,
|
||||||
props: P,
|
|
||||||
cfg: ServeConfig,
|
cfg: ServeConfig,
|
||||||
server_context: DioxusServerContext,
|
server_context: DioxusServerContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: Clone + Serialize + Send + Sync + 'static> dioxus_ssr::incremental::WrapBody
|
impl dioxus_ssr::incremental::WrapBody for FullstackRenderer {
|
||||||
for FullstackRenderer<P>
|
|
||||||
{
|
|
||||||
fn render_before_body<R: std::io::Write>(
|
fn render_before_body<R: std::io::Write>(
|
||||||
&self,
|
&self,
|
||||||
to: &mut R,
|
to: &mut R,
|
||||||
|
@ -242,9 +238,10 @@ impl<P: Clone + Serialize + Send + Sync + 'static> dioxus_ssr::incremental::Wrap
|
||||||
to: &mut R,
|
to: &mut R,
|
||||||
) -> Result<(), dioxus_ssr::incremental::IncrementalRendererError> {
|
) -> Result<(), dioxus_ssr::incremental::IncrementalRendererError> {
|
||||||
// serialize the props
|
// serialize the props
|
||||||
crate::html_storage::serialize::encode_props_in_element(&self.cfg.props, to).map_err(
|
// TODO: restore props serialization
|
||||||
|err| dioxus_ssr::incremental::IncrementalRendererError::Other(Box::new(err)),
|
// 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
|
// serialize the server state
|
||||||
crate::html_storage::serialize::encode_in_element(
|
crate::html_storage::serialize::encode_in_element(
|
||||||
&*self.server_context.html_data().map_err(|_| {
|
&*self.server_context.html_data().map_err(|_| {
|
||||||
|
|
|
@ -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 =
|
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) {
|
let mut args: ServerFnArgs = match syn::parse(args) {
|
||||||
Ok(args) => args,
|
Ok(args) => args,
|
||||||
Err(e) => return e.to_compile_error().into(),
|
Err(e) => return e.to_compile_error().into(),
|
||||||
|
@ -125,7 +125,7 @@ pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||||
#tokens
|
#tokens
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#server_fn_path::inventory::submit! {
|
#server_fn_path::inventory::submit! {
|
||||||
::dioxus_fullstack::prelude::ServerFnMiddleware {
|
::dioxus::fullstack::prelude::ServerFnMiddleware {
|
||||||
prefix: #struct_name::PREFIX,
|
prefix: #struct_name::PREFIX,
|
||||||
url: #struct_name::URL,
|
url: #struct_name::URL,
|
||||||
middleware: || vec![
|
middleware: || vec![
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::fs_cache::ValidCachedPath;
|
use crate::fs_cache::ValidCachedPath;
|
||||||
use dioxus_core::{Element, VirtualDom};
|
use dioxus_core::{AnyProps, CrossPlatformConfig, VirtualDom};
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
|
@ -69,18 +69,17 @@ impl IncrementalRenderer {
|
||||||
self.invalidate_after.is_some()
|
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,
|
&'a mut self,
|
||||||
route: String,
|
route: String,
|
||||||
comp: fn(P) -> Element,
|
dioxus_config: CrossPlatformConfig<P>,
|
||||||
props: P,
|
|
||||||
output: &'a mut (impl AsyncWrite + Unpin + Send),
|
output: &'a mut (impl AsyncWrite + Unpin + Send),
|
||||||
rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
|
rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
|
||||||
renderer: &'a R,
|
renderer: &'a R,
|
||||||
) -> Result<RenderFreshness, IncrementalRendererError> {
|
) -> Result<RenderFreshness, IncrementalRendererError> {
|
||||||
let mut html_buffer = WriteBuffer { buffer: Vec::new() };
|
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);
|
vdom.in_runtime(crate::eval::init_eval);
|
||||||
rebuild_with(&mut vdom).await;
|
rebuild_with(&mut vdom).await;
|
||||||
|
|
||||||
|
@ -168,11 +167,10 @@ impl IncrementalRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render a route or get it from cache.
|
/// 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,
|
&mut self,
|
||||||
route: String,
|
route: String,
|
||||||
component: fn(P) -> Element,
|
dioxus_config: CrossPlatformConfig<P>,
|
||||||
props: P,
|
|
||||||
output: &mut (impl AsyncWrite + Unpin + std::marker::Send),
|
output: &mut (impl AsyncWrite + Unpin + std::marker::Send),
|
||||||
rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
|
rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
|
||||||
renderer: &R,
|
renderer: &R,
|
||||||
|
@ -183,7 +181,7 @@ impl IncrementalRenderer {
|
||||||
} else {
|
} else {
|
||||||
// if not, create it
|
// if not, create it
|
||||||
let freshness = self
|
let freshness = self
|
||||||
.render_and_cache(route, component, props, output, rebuild_with, renderer)
|
.render_and_cache(route, dioxus_config, output, rebuild_with, renderer)
|
||||||
.await?;
|
.await?;
|
||||||
tracing::trace!("cache miss");
|
tracing::trace!("cache miss");
|
||||||
Ok(freshness)
|
Ok(freshness)
|
||||||
|
|
|
@ -60,7 +60,7 @@ use std::rc::Rc;
|
||||||
pub use crate::cfg::Config;
|
pub use crate::cfg::Config;
|
||||||
#[cfg(feature = "file_engine")]
|
#[cfg(feature = "file_engine")]
|
||||||
pub use crate::file_engine::WebFileEngineExt;
|
pub use crate::file_engine::WebFileEngineExt;
|
||||||
use dioxus_core::CrossPlatformConfig;
|
use dioxus_core::{AnyProps, CrossPlatformConfig};
|
||||||
use futures_util::{
|
use futures_util::{
|
||||||
future::{select, Either},
|
future::{select, Either},
|
||||||
pin_mut, FutureExt, StreamExt,
|
pin_mut, FutureExt, StreamExt,
|
||||||
|
@ -99,7 +99,10 @@ mod rehydrate;
|
||||||
/// wasm_bindgen_futures::spawn_local(app_fut);
|
/// 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");
|
tracing::info!("Starting up");
|
||||||
|
|
||||||
let mut dom = dioxus_config.build_vdom();
|
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();
|
let (tx, mut rx) = futures_channel::mpsc::unbounded();
|
||||||
|
|
||||||
#[cfg(feature = "hydrate")]
|
#[cfg(feature = "hydrate")]
|
||||||
let should_hydrate = cfg.hydrate;
|
let should_hydrate = web_config.hydrate;
|
||||||
#[cfg(not(feature = "hydrate"))]
|
#[cfg(not(feature = "hydrate"))]
|
||||||
let should_hydrate = false;
|
let should_hydrate = false;
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@ use crate::Config;
|
||||||
/// The web renderer platform
|
/// The web renderer platform
|
||||||
pub struct WebPlatform;
|
pub struct WebPlatform;
|
||||||
|
|
||||||
impl PlatformBuilder for WebPlatform {
|
impl<P: AnyProps> PlatformBuilder<P> for WebPlatform {
|
||||||
type Config = Config;
|
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 {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
crate::run_with_props(config, platform_config).await;
|
crate::run_with_props(config, platform_config).await;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue