mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
work on restoring fullstack
This commit is contained in:
parent
205a005142
commit
0c532c5e0c
20 changed files with 172 additions and 304 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ use serde::{Deserialize, Serialize};
|
|||
#[tokio::main]
|
||||
async fn main() {
|
||||
pre_cache_static_routes_with_props(
|
||||
&ServeConfigBuilder::new_with_router(dioxus_fullstack::router::FullstackRouterConfig::<
|
||||
Route,
|
||||
>::default())
|
||||
&ServerConfig::new_with_router(
|
||||
dioxus_fullstack::router::FullstackRouterConfig::<Route>::default(),
|
||||
)
|
||||
.assets_path("docs")
|
||||
.incremental(IncrementalRendererConfig::default().static_dir("docs"))
|
||||
.build(),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! # Example
|
||||
//! ```rust
|
||||
//! #![allow(non_snake_case)]
|
||||
//! use dioxus::prelude::*;
|
||||
//! use dioxus_lib::prelude::*;
|
||||
//! use dioxus_fullstack::prelude::*;
|
||||
//!
|
||||
//! fn main() {
|
||||
|
@ -20,7 +20,7 @@
|
|||
//! .serve(
|
||||
//! axum::Router::new()
|
||||
//! // Server side render the application, serve static assets, and register server functions
|
||||
//! .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
|
||||
//! .serve_dioxus_application("", ServerConfig::new(app, ()))
|
||||
//! .into_make_service(),
|
||||
//! )
|
||||
//! .await
|
||||
|
@ -78,7 +78,7 @@ pub trait DioxusRouterExt<S> {
|
|||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_lib::prelude::*;
|
||||
/// use dioxus_fullstack::prelude::*;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
|
@ -115,7 +115,7 @@ pub trait DioxusRouterExt<S> {
|
|||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_lib::prelude::*;
|
||||
/// use dioxus_fullstack::prelude::*;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
|
@ -163,7 +163,7 @@ pub trait DioxusRouterExt<S> {
|
|||
/// # Example
|
||||
/// ```rust
|
||||
/// #![allow(non_snake_case)]
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_lib::prelude::*;
|
||||
/// use dioxus_fullstack::prelude::*;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
|
@ -173,7 +173,7 @@ pub trait DioxusRouterExt<S> {
|
|||
/// .serve(
|
||||
/// axum::Router::new()
|
||||
/// // Server side render the application, serve static assets, and register server functions
|
||||
/// .serve_static_assets(ServeConfigBuilder::new(app, ()))
|
||||
/// .serve_static_assets("dist")
|
||||
/// // Server render the application
|
||||
/// // ...
|
||||
/// .into_make_service(),
|
||||
|
@ -194,7 +194,7 @@ pub trait DioxusRouterExt<S> {
|
|||
/// # Example
|
||||
/// ```rust
|
||||
/// #![allow(non_snake_case)]
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_lib::prelude::*;
|
||||
/// use dioxus_fullstack::prelude::*;
|
||||
///
|
||||
/// #[tokio::main]
|
||||
|
@ -204,7 +204,7 @@ pub trait DioxusRouterExt<S> {
|
|||
/// .serve(
|
||||
/// axum::Router::new()
|
||||
/// // Server side render the application, serve static assets, and register server functions
|
||||
/// .serve_dioxus_application("", ServeConfigBuilder::new(app, ()))
|
||||
/// .serve_dioxus_application("", ServerConfig::new(app, ()))
|
||||
/// .into_make_service(),
|
||||
/// )
|
||||
/// .await
|
||||
|
@ -376,7 +376,7 @@ fn apply_request_parts_to_response<B>(
|
|||
/// use std::sync::{Arc, Mutex};
|
||||
///
|
||||
/// use axum::routing::get;
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_lib::prelude::*;
|
||||
/// use dioxus_fullstack::{axum_adapter::render_handler_with_context, prelude::*};
|
||||
///
|
||||
/// fn app() -> Element {
|
||||
|
@ -387,7 +387,7 @@ fn apply_request_parts_to_response<B>(
|
|||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() {
|
||||
/// let cfg = ServeConfigBuilder::new(app, ())
|
||||
/// let cfg = ServerConfig::new(app, ())
|
||||
/// .assets_path("dist")
|
||||
/// .build();
|
||||
/// let ssr_state = SSRState::new(&cfg);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
/// }
|
||||
///
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use dioxus_core::prelude::*;
|
||||
use dioxus_lib::prelude::*;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::any::Any;
|
||||
use std::cell::Cell;
|
||||
|
@ -70,10 +70,10 @@ where
|
|||
|
||||
// // Cancel the current future
|
||||
// if let Some(current) = state.task.take() {
|
||||
// cx.remove_future(current);
|
||||
// remove_future(current);
|
||||
// }
|
||||
|
||||
// state.task.set(Some(cx.push_future(async move {
|
||||
// state.task.set(Some(push_future(async move {
|
||||
// let data;
|
||||
// #[cfg(feature = "ssr")]
|
||||
// {
|
||||
|
@ -115,36 +115,36 @@ pub struct UseServerFuture<T> {
|
|||
}
|
||||
|
||||
impl<T> UseServerFuture<T> {
|
||||
// /// Restart the future with new dependencies.
|
||||
// ///
|
||||
// /// Will not cancel the previous future, but will ignore any values that it
|
||||
// /// generates.
|
||||
// pub fn restart(&self) {
|
||||
// self.needs_regen.set(true);
|
||||
// (self.update)();
|
||||
// }
|
||||
/// 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<Task> {
|
||||
// self.task.get()
|
||||
// }
|
||||
/// Get the ID of the future in Dioxus' internal scheduler
|
||||
pub fn task(&self) -> Option<Task> {
|
||||
self.task.get()
|
||||
}
|
||||
|
||||
// /// Get the current state of the future.
|
||||
// pub fn reloading(&self) -> bool {
|
||||
// self.task.get().is_some()
|
||||
// }
|
||||
/// Get the current state of the future.
|
||||
pub fn reloading(&self) -> bool {
|
||||
self.task.get().is_some()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use dioxus::prelude::Template;
|
||||
use dioxus_lib::prelude::Template;
|
||||
use tokio::sync::{
|
||||
watch::{channel, Receiver},
|
||||
RwLock,
|
||||
|
@ -9,7 +9,7 @@ use tokio::sync::{
|
|||
#[derive(Clone)]
|
||||
pub struct HotReloadState {
|
||||
// The cache of all templates that have been modified since the last time we checked
|
||||
pub(crate) templates: Arc<RwLock<std::collections::HashSet<dioxus::prelude::Template>>>,
|
||||
pub(crate) templates: Arc<RwLock<std::collections::HashSet<dioxus_lib::prelude::Template>>>,
|
||||
// The channel to send messages to the hot reload thread
|
||||
pub(crate) message_receiver: Receiver<Option<Template>>,
|
||||
}
|
||||
|
|
|
@ -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<Props: Clone> {
|
||||
component: Component<Props>,
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
props: Props,
|
||||
/// The desktop renderer platform
|
||||
pub struct FullstackPlatform;
|
||||
|
||||
impl<Props: Clone + 'static> dioxus_core::PlatformBuilder<Props> for FullstackPlatform {
|
||||
type Config = Config;
|
||||
|
||||
fn launch(config: dioxus_core::CrossPlatformConfig<Props>, platform_config: Self::Config) {}
|
||||
}
|
||||
|
||||
/// Settings for a fullstack app.
|
||||
pub struct Config {
|
||||
#[cfg(feature = "ssr")]
|
||||
server_fn_route: &'static str,
|
||||
#[cfg(feature = "ssr")]
|
||||
server_cfg: ServeConfigBuilder<Props>,
|
||||
server_cfg: ServeConfigBuilder,
|
||||
#[cfg(feature = "ssr")]
|
||||
addr: std::net::SocketAddr,
|
||||
#[cfg(feature = "web")]
|
||||
|
@ -22,38 +26,29 @@ pub struct LaunchBuilder<Props: Clone> {
|
|||
desktop_cfg: dioxus_desktop::Config,
|
||||
}
|
||||
|
||||
impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static>
|
||||
LaunchBuilder<Props>
|
||||
{
|
||||
/// Create a new builder for a fullstack app.
|
||||
pub fn new(component: Component<Props>) -> Self
|
||||
where
|
||||
Props: Default,
|
||||
{
|
||||
Self::new_with_props(component, Default::default())
|
||||
}
|
||||
|
||||
/// Create a new builder for a fullstack app with props.
|
||||
pub fn new_with_props(component: Component<Props>, props: Props) -> Self
|
||||
where
|
||||
Props: Default,
|
||||
{
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
component,
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
props,
|
||||
#[cfg(feature = "ssr")]
|
||||
server_fn_route: "",
|
||||
#[cfg(feature = "ssr")]
|
||||
addr: std::net::SocketAddr::from(([127, 0, 0, 1], 8080)),
|
||||
#[cfg(feature = "ssr")]
|
||||
server_cfg: ServeConfigBuilder::new(component, props),
|
||||
server_cfg: ServeConfigBuilder::new(),
|
||||
#[cfg(feature = "web")]
|
||||
web_cfg: dioxus_web::Config::default(),
|
||||
#[cfg(feature = "desktop")]
|
||||
desktop_cfg: dioxus_desktop::Config::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Create a new config for a fullstack app.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Set the address to serve the app on.
|
||||
#[cfg(feature = "ssr")]
|
||||
|
@ -82,7 +77,7 @@ impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync
|
|||
|
||||
/// Set the server config.
|
||||
#[cfg(feature = "ssr")]
|
||||
pub fn server_cfg(self, server_cfg: ServeConfigBuilder<Props>) -> Self {
|
||||
pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self {
|
||||
Self { server_cfg, ..self }
|
||||
}
|
||||
|
||||
|
@ -210,17 +205,3 @@ impl<Props: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "router")]
|
||||
impl<R: Routable> LaunchBuilder<crate::router::FullstackRouterConfig<R>>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static,
|
||||
{
|
||||
/// Create a new launch builder for the given router.
|
||||
pub fn router() -> Self {
|
||||
let component = crate::router::RouteWithCfg::<R>;
|
||||
let props = crate::router::FullstackRouterConfig::default();
|
||||
Self::new_with_props(component, props)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"))]
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
//! A shared pool of renderers for efficient server side rendering.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::render::dioxus_core::NoOpMutations;
|
||||
use crate::server_context::SERVER_CONTEXT;
|
||||
use dioxus::prelude::VirtualDom;
|
||||
use dioxus_lib::prelude::VirtualDom;
|
||||
use dioxus_ssr::{
|
||||
incremental::{IncrementalRendererConfig, RenderFreshness, WrapBody},
|
||||
Renderer,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
use crate::prelude::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_lib::prelude::*;
|
||||
|
||||
enum SsrRendererPool {
|
||||
Renderer(RwLock<Vec<Renderer>>),
|
||||
|
@ -45,15 +45,17 @@ impl SsrRendererPool {
|
|||
.expect("couldn't spawn runtime")
|
||||
.block_on(async move {
|
||||
let mut vdom = VirtualDom::new_with_props(component, props);
|
||||
// Make sure the evaluator is initialized
|
||||
dioxus_ssr::eval::init_eval(vdom.base_scope());
|
||||
vdom.in_runtime(|| {
|
||||
// Make sure the evaluator is initialized
|
||||
dioxus_ssr::eval::init_eval();
|
||||
});
|
||||
let mut to = WriteBuffer { buffer: Vec::new() };
|
||||
// before polling the future, we need to set the context
|
||||
let prev_context =
|
||||
SERVER_CONTEXT.with(|ctx| ctx.replace(server_context));
|
||||
// poll the future, which may call server_context()
|
||||
tracing::info!("Rebuilding vdom");
|
||||
let _ = vdom.rebuild();
|
||||
let _ = vdom.rebuild(&mut NoOpMutations);
|
||||
vdom.wait_for_suspense().await;
|
||||
tracing::info!("Suspense resolved");
|
||||
// after polling the future, we need to restore the context
|
||||
|
@ -119,7 +121,7 @@ impl SsrRendererPool {
|
|||
.with(|ctx| ctx.replace(Box::new(server_context)));
|
||||
// poll the future, which may call server_context()
|
||||
tracing::info!("Rebuilding vdom");
|
||||
let _ = vdom.rebuild();
|
||||
let _ = vdom.rebuild(&mut NoOpMutations);
|
||||
vdom.wait_for_suspense().await;
|
||||
tracing::info!("Suspense resolved");
|
||||
// after polling the future, we need to restore the context
|
||||
|
@ -195,16 +197,18 @@ impl SSRState {
|
|||
route: String,
|
||||
cfg: &'a ServeConfig<P>,
|
||||
server_context: &'a DioxusServerContext,
|
||||
app: Component<P>,
|
||||
props: P,
|
||||
) -> impl std::future::Future<
|
||||
Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
|
||||
> + Send
|
||||
+ 'a {
|
||||
async move {
|
||||
let ServeConfig { app, props, .. } = cfg;
|
||||
let ServeConfig { .. } = cfg;
|
||||
|
||||
let (freshness, html) = self
|
||||
.renderers
|
||||
.render_to(cfg, route, *app, props.clone(), server_context)
|
||||
.render_to(cfg, route, app, props, server_context)
|
||||
.await?;
|
||||
|
||||
Ok(RenderResponse { html, freshness })
|
||||
|
@ -213,7 +217,9 @@ impl SSRState {
|
|||
}
|
||||
|
||||
struct FullstackRenderer<P: Clone + Send + Sync + 'static> {
|
||||
cfg: ServeConfig<P>,
|
||||
component: Component<P>,
|
||||
props: P,
|
||||
cfg: ServeConfig,
|
||||
server_context: DioxusServerContext,
|
||||
}
|
||||
|
||||
|
@ -338,28 +344,6 @@ fn incremental_pre_renderer(
|
|||
renderer
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "ssr", feature = "router"))]
|
||||
/// Pre-caches all static routes
|
||||
pub async fn pre_cache_static_routes_with_props<Rt>(
|
||||
cfg: &crate::prelude::ServeConfig<crate::router::FullstackRouterConfig<Rt>>,
|
||||
) -> Result<(), dioxus_ssr::incremental::IncrementalRendererError>
|
||||
where
|
||||
Rt: dioxus_router::prelude::Routable + Send + Sync + Serialize,
|
||||
<Rt as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
let wrapper = FullstackRenderer {
|
||||
cfg: cfg.clone(),
|
||||
server_context: Default::default(),
|
||||
};
|
||||
let mut renderer = incremental_pre_renderer(
|
||||
cfg.incremental
|
||||
.as_ref()
|
||||
.expect("incremental renderer config must be set to pre-cache static routes"),
|
||||
);
|
||||
|
||||
dioxus_router::incremental::pre_cache_static_routes::<Rt, _>(&mut renderer, &wrapper).await
|
||||
}
|
||||
|
||||
struct WriteBuffer {
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
//! Fullstack router intigration
|
||||
#![allow(non_snake_case)]
|
||||
use dioxus::prelude::*;
|
||||
|
||||
/// Used by the launch macro
|
||||
#[doc(hidden)]
|
||||
pub fn RouteWithCfg<R>(props: FullstackRouterConfig<R>) -> Element
|
||||
where
|
||||
R: dioxus_router::prelude::Routable,
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
use dioxus_router::prelude::RouterConfig;
|
||||
|
||||
let cfg = props;
|
||||
rsx! {
|
||||
dioxus_router::prelude::Router::<R> {
|
||||
config: move || {
|
||||
RouterConfig::default()
|
||||
.failure_external_navigation(cfg.failure_external_navigation)
|
||||
.history({
|
||||
#[cfg(feature = "ssr")]
|
||||
let history = dioxus_router::prelude::MemoryHistory::with_initial_path(
|
||||
crate::prelude::server_context()
|
||||
.request_parts()
|
||||
.unwrap()
|
||||
.uri
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::error!("Failed to parse uri: {}", err);
|
||||
"/"
|
||||
.parse()
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("Failed to parse uri: {}", err);
|
||||
})
|
||||
}),
|
||||
);
|
||||
#[cfg(not(feature = "ssr"))]
|
||||
let history = dioxus_router::prelude::WebHistory::new(
|
||||
None,
|
||||
cfg.scroll_restoration,
|
||||
);
|
||||
history
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_external_navigation_handler() -> fn() -> Element {
|
||||
dioxus_router::prelude::FailureExternalNavigation
|
||||
}
|
||||
|
||||
/// The configuration for the router
|
||||
#[derive(Props, serde::Serialize, serde::Deserialize)]
|
||||
pub struct FullstackRouterConfig<R>
|
||||
where
|
||||
R: dioxus_router::prelude::Routable,
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
#[serde(skip)]
|
||||
#[serde(default = "default_external_navigation_handler")]
|
||||
failure_external_navigation: fn() -> Element,
|
||||
scroll_restoration: bool,
|
||||
#[serde(skip)]
|
||||
phantom: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<R> Clone for FullstackRouterConfig<R>
|
||||
where
|
||||
R: dioxus_router::prelude::Routable,
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Copy for FullstackRouterConfig<R>
|
||||
where
|
||||
R: dioxus_router::prelude::Routable,
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
}
|
||||
|
||||
impl<R> Default for FullstackRouterConfig<R>
|
||||
where
|
||||
R: dioxus_router::prelude::Routable,
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
failure_external_navigation: dioxus_router::prelude::FailureExternalNavigation,
|
||||
scroll_restoration: true,
|
||||
phantom: std::marker::PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,13 +7,11 @@ use std::fs::File;
|
|||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_lib::prelude::*;
|
||||
|
||||
/// A ServeConfig is used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`].
|
||||
#[derive(Clone)]
|
||||
pub struct ServeConfigBuilder<P: Clone> {
|
||||
pub(crate) app: Component<P>,
|
||||
pub(crate) props: P,
|
||||
pub struct ServeConfigBuilder {
|
||||
pub(crate) root_id: Option<&'static str>,
|
||||
pub(crate) index_path: Option<&'static str>,
|
||||
pub(crate) assets_path: Option<&'static str>,
|
||||
|
@ -41,24 +39,10 @@ impl dioxus_ssr::incremental::WrapBody for EmptyIncrementalRenderTemplate {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "router")]
|
||||
impl<R> ServeConfigBuilder<FullstackRouterConfig<R>>
|
||||
where
|
||||
R: dioxus_router::prelude::Routable,
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
/// Create a new ServeConfigBuilder to serve a router on the server.
|
||||
pub fn new_with_router(cfg: FullstackRouterConfig<R>) -> Self {
|
||||
Self::new(RouteWithCfg::<R>, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Clone> ServeConfigBuilder<P> {
|
||||
impl ServeConfigBuilder {
|
||||
/// Create a new ServeConfigBuilder with the root component and props to render on the server.
|
||||
pub fn new(app: Component<P>, props: P) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
app,
|
||||
props,
|
||||
root_id: None,
|
||||
index_path: None,
|
||||
assets_path: None,
|
||||
|
@ -91,7 +75,7 @@ impl<P: Clone> ServeConfigBuilder<P> {
|
|||
}
|
||||
|
||||
/// Build the ServeConfig
|
||||
pub fn build(self) -> ServeConfig<P> {
|
||||
pub fn build(self) -> ServeConfig {
|
||||
let assets_path = self.assets_path.unwrap_or("dist");
|
||||
|
||||
let index_path = self
|
||||
|
@ -104,8 +88,6 @@ impl<P: Clone> ServeConfigBuilder<P> {
|
|||
let index = load_index_html(index_path, root_id);
|
||||
|
||||
ServeConfig {
|
||||
app: self.app,
|
||||
props: self.props,
|
||||
index,
|
||||
assets_path,
|
||||
incremental: self.incremental,
|
||||
|
@ -146,17 +128,22 @@ pub(crate) struct IndexHtml {
|
|||
/// Used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`].
|
||||
/// See [`ServeConfigBuilder`] to create a ServeConfig
|
||||
#[derive(Clone)]
|
||||
pub struct ServeConfig<P: Clone> {
|
||||
pub(crate) app: Component<P>,
|
||||
pub(crate) props: P,
|
||||
pub struct ServeConfig {
|
||||
pub(crate) index: IndexHtml,
|
||||
pub(crate) assets_path: &'static str,
|
||||
pub(crate) incremental:
|
||||
Option<std::sync::Arc<dioxus_ssr::incremental::IncrementalRendererConfig>>,
|
||||
}
|
||||
|
||||
impl<P: Clone> From<ServeConfigBuilder<P>> for ServeConfig<P> {
|
||||
fn from(builder: ServeConfigBuilder<P>) -> Self {
|
||||
impl ServeConfig {
|
||||
/// Create a new builder for a ServeConfig
|
||||
pub fn builder() -> ServeConfigBuilder {
|
||||
ServeConfigBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ServeConfigBuilder> for ServeConfig {
|
||||
fn from(builder: ServeConfigBuilder) -> Self {
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -46,6 +46,43 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! default_history {
|
||||
($initial_route:ident) => {
|
||||
{
|
||||
// If we are on wasm32 and the web feature is enabled, use the web history.
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
return Box::<AnyHistoryProviderImplWrapper::<WebHistory::<R>>>::default();
|
||||
// If we are using dioxus fullstack and the ssr feature is enabled, use the memory history with the initial path set to the current path in fullstack
|
||||
#[cfg(all(feature = "fullstack", feature = "ssr"))]
|
||||
return dioxus_router::prelude::MemoryHistory::with_initial_path(
|
||||
dioxus_fullstack::prelude::server_context()
|
||||
.request_parts()
|
||||
.unwrap()
|
||||
.uri
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::error!("Failed to parse uri: {}", err);
|
||||
"/"
|
||||
.parse()
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("Failed to parse uri: {}", err);
|
||||
})
|
||||
}),
|
||||
);
|
||||
// If we are not on wasm32 and the liveview feature is enabled, use the liveview history.
|
||||
#[cfg(all(feature = "liveview"))]
|
||||
return Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new($initial_route)));
|
||||
// Otherwise use the memory history.
|
||||
#[cfg(all(
|
||||
not(all(target_arch = "wasm32", feature = "web")),
|
||||
not(all(feature = "liveview", not(target_arch = "wasm32"))),
|
||||
))]
|
||||
Box::new(AnyHistoryProviderImplWrapper::new(MemoryHistory::with_initial_path($initial_route)))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable + Clone> RouterConfig<R>
|
||||
where
|
||||
|
@ -53,18 +90,13 @@ where
|
|||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
pub(crate) fn get_history(self) -> Box<dyn HistoryProvider<R>> {
|
||||
self.history.unwrap_or_else(|| {
|
||||
#[cfg(all(not(feature = "liveview"), target_arch = "wasm32", feature = "web"))]
|
||||
let history = Box::<WebHistory<R>>::default();
|
||||
#[cfg(all(
|
||||
not(feature = "liveview"),
|
||||
any(not(target_arch = "wasm32"), not(feature = "web"))
|
||||
))]
|
||||
let history = Box::<MemoryHistory<R>>::default();
|
||||
#[cfg(feature = "liveview")]
|
||||
let history = Box::<LiveviewHistory<R>>::default();
|
||||
history
|
||||
})
|
||||
#[allow(unused)]
|
||||
let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err|
|
||||
panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err)
|
||||
));
|
||||
self.history
|
||||
.take()
|
||||
.unwrap_or_else(|| default_history!(initial_route))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,25 +121,13 @@ where
|
|||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
pub(crate) fn take_history(&mut self) -> Box<dyn AnyHistoryProvider> {
|
||||
self.history.take().unwrap_or_else(|| {
|
||||
#[allow(unused)]
|
||||
#[allow(unused)]
|
||||
let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err|
|
||||
panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err)
|
||||
));
|
||||
// If we are on wasm32 and the web feature is enabled, use the web history.
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
let history = Box::<AnyHistoryProviderImplWrapper::<WebHistory::<R>>>::default();
|
||||
// If we are not on wasm32 and the liveview feature is enabled, use the liveview history.
|
||||
#[cfg(all(feature = "liveview", not(target_arch = "wasm32")))]
|
||||
let history = Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new(initial_route)));
|
||||
// If neither of the above are true, use the memory history.
|
||||
#[cfg(all(
|
||||
not(all(target_arch = "wasm32", feature = "web")),
|
||||
not(all(feature = "liveview", not(target_arch = "wasm32"))),
|
||||
))]
|
||||
let history = Box::new(AnyHistoryProviderImplWrapper::new(MemoryHistory::with_initial_path(initial_route)));
|
||||
history
|
||||
})
|
||||
self.history
|
||||
.take()
|
||||
.unwrap_or_else(|| default_history!(initial_route))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue