fix the fullstack platform with the new launch API
This commit is contained in:
1 parent
cb5a43c120
commit
a323962a22
7 files changed
+281
-255
No files matched your search
@@ -11,7 +11,7 @@ use tao::event::{Event, StartCause, WindowEvent};
|
|||||||
///
|
///
|
||||||
/// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime
|
/// This will block the main thread, and *must* be spawned on the main thread. This function does not assume any runtime
|
||||||
/// and is equivalent to calling launch_with_props with the tokio feature disabled.
|
/// and is equivalent to calling launch_with_props with the tokio feature disabled.
|
||||||
pub fn launch_with_props_blocking(virtual_dom: VirtualDom, desktop_config: Config) {
|
pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Config) {
|
||||||
let (event_loop, mut app) = App::new(desktop_config, virtual_dom);
|
let (event_loop, mut app) = App::new(desktop_config, virtual_dom);
|
||||||
|
|
||||||
event_loop.run(move |window_event, _, control_flow| {
|
event_loop.run(move |window_event, _, control_flow| {
|
||||||
@@ -48,6 +48,21 @@ pub fn launch_with_props_blocking(virtual_dom: VirtualDom, desktop_config: Confi
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Launches the WebView and runs the event loop, with configuration and root props.
|
||||||
|
pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) {
|
||||||
|
#[cfg(feature = "tokio")]
|
||||||
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.block_on(tokio::task::unconstrained(async move {
|
||||||
|
launch_virtual_dom_blocking(virtual_dom, desktop_config)
|
||||||
|
}));
|
||||||
|
|
||||||
|
#[cfg(not(feature = "tokio"))]
|
||||||
|
launch_virtual_dom_blocking(config, desktop_config)
|
||||||
|
}
|
||||||
|
|
||||||
/// Launches the WebView and runs the event loop, with configuration and root props.
|
/// Launches the WebView and runs the event loop, with configuration and root props.
|
||||||
pub fn launch(
|
pub fn launch(
|
||||||
root: fn() -> Element,
|
root: fn() -> Element,
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ use axum::{
|
|||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
use dioxus_lib::prelude::dioxus_core::{AnyProps, CrossPlatformConfig};
|
use dioxus_lib::prelude::dioxus_core::AnyProps;
|
||||||
|
use dioxus_lib::prelude::VirtualDom;
|
||||||
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;
|
||||||
@@ -216,11 +217,11 @@ pub trait DioxusRouterExt<S> {
|
|||||||
/// todo!()
|
/// todo!()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
|
fn serve_dioxus_application(
|
||||||
self,
|
self,
|
||||||
server_fn_route: &'static str,
|
server_fn_route: &'static str,
|
||||||
cfg: impl Into<ServeConfig>,
|
cfg: impl Into<ServeConfig>,
|
||||||
dioxus_config: CrossPlatformConfig<P>,
|
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
) -> Self;
|
) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,11 +316,11 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
|
fn serve_dioxus_application(
|
||||||
self,
|
self,
|
||||||
server_fn_route: &'static str,
|
server_fn_route: &'static str,
|
||||||
cfg: impl Into<ServeConfig>,
|
cfg: impl Into<ServeConfig>,
|
||||||
dioxus_config: CrossPlatformConfig<P>,
|
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cfg = cfg.into();
|
let cfg = cfg.into();
|
||||||
let ssr_state = SSRState::new(&cfg);
|
let ssr_state = SSRState::new(&cfg);
|
||||||
@@ -328,7 +329,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, dioxus_config, ssr_state)))
|
.fallback(get(render_handler).with_state((cfg, Arc::new(build_virtual_dom), ssr_state)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect_hot_reload(self) -> Self {
|
fn connect_hot_reload(self) -> Self {
|
||||||
@@ -418,15 +419,12 @@ fn apply_request_parts_to_response<B>(
|
|||||||
/// .unwrap();
|
/// .unwrap();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn render_handler_with_context<
|
pub async fn render_handler_with_context<F: FnMut(&mut DioxusServerContext)>(
|
||||||
P: AnyProps + Clone + Send + Sync + 'static,
|
State((mut inject_context, cfg, ssr_state, virtual_dom_factory)): State<(
|
||||||
F: FnMut(&mut DioxusServerContext),
|
|
||||||
>(
|
|
||||||
State((mut inject_context, cfg, ssr_state, dioxus_config)): State<(
|
|
||||||
F,
|
F,
|
||||||
ServeConfig,
|
ServeConfig,
|
||||||
SSRState,
|
SSRState,
|
||||||
CrossPlatformConfig<P>,
|
Arc<dyn Fn() -> VirtualDom + Send + Sync>,
|
||||||
)>,
|
)>,
|
||||||
request: Request<Body>,
|
request: Request<Body>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
@@ -437,7 +435,7 @@ pub async fn render_handler_with_context<
|
|||||||
inject_context(&mut server_context);
|
inject_context(&mut server_context);
|
||||||
|
|
||||||
match ssr_state
|
match ssr_state
|
||||||
.render(url, &cfg, dioxus_config, &server_context)
|
.render(url, &cfg, move || virtual_dom_factory(), &server_context)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(rendered) => {
|
Ok(rendered) => {
|
||||||
@@ -456,12 +454,16 @@ pub async fn render_handler_with_context<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// SSR renderer handler for Axum
|
/// SSR renderer handler for Axum
|
||||||
pub async fn render_handler<P: AnyProps + Clone + Send + Sync + 'static>(
|
pub async fn render_handler(
|
||||||
State((cfg, dioxus_config, ssr_state)): State<(ServeConfig, CrossPlatformConfig<P>, SSRState)>,
|
State((cfg, virtual_dom_factory, ssr_state)): State<(
|
||||||
|
ServeConfig,
|
||||||
|
Arc<dyn Fn() -> VirtualDom + Send + Sync>,
|
||||||
|
SSRState,
|
||||||
|
)>,
|
||||||
request: Request<Body>,
|
request: Request<Body>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
render_handler_with_context(
|
render_handler_with_context(
|
||||||
State((|_: &mut _| (), cfg, ssr_state, dioxus_config)),
|
State((|_: &mut _| (), cfg, ssr_state, virtual_dom_factory)),
|
||||||
request,
|
request,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
//! Launch helper macros for fullstack apps
|
||||||
|
#![allow(unused)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
use dioxus_lib::prelude::{dioxus_core::AnyProps, *};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Settings for a fullstack app.
|
||||||
|
pub struct Config {
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
server_fn_route: &'static str,
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
server_cfg: ServeConfigBuilder,
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
addr: std::net::SocketAddr,
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
web_cfg: dioxus_web::Config,
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
desktop_cfg: dioxus_desktop::Config,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::derivable_impls)]
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
#[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(),
|
||||||
|
#[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")]
|
||||||
|
pub fn addr(self, addr: impl Into<std::net::SocketAddr>) -> Self {
|
||||||
|
let addr = addr.into();
|
||||||
|
Self { addr, ..self }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the route to the server functions.
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
pub fn server_fn_route(self, server_fn_route: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
server_fn_route,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the incremental renderer config.
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
pub fn incremental(self, cfg: IncrementalRendererConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
server_cfg: self.server_cfg.incremental(cfg),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the server config.
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self {
|
||||||
|
Self { server_cfg, ..self }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the web config.
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
pub fn web_cfg(self, web_cfg: dioxus_web::Config) -> Self {
|
||||||
|
Self { web_cfg, ..self }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the desktop config.
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
pub fn desktop_cfg(self, desktop_cfg: dioxus_desktop::Config) -> Self {
|
||||||
|
Self {
|
||||||
|
desktop_cfg,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Launch the app.
|
||||||
|
pub fn launch(self, build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static) {
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
tokio::runtime::Runtime::new()
|
||||||
|
.unwrap()
|
||||||
|
.block_on(async move {
|
||||||
|
self.launch_server(build_virtual_dom).await;
|
||||||
|
});
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
self.launch_web(build_virtual_dom);
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
self.launch_desktop(build_virtual_dom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
/// Launch the web application
|
||||||
|
pub fn launch_web(self, build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static) {
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
|
{
|
||||||
|
let cfg = self.web_cfg.hydrate(true);
|
||||||
|
dioxus_web::run(
|
||||||
|
// TODO: this should pull the props from the document
|
||||||
|
build_virtual_dom(),
|
||||||
|
cfg,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
/// Launch the web application
|
||||||
|
pub fn launch_desktop<P: AnyProps>(self, build_virtual_dom: impl Fn() -> VirtualDom + 'static) {
|
||||||
|
let cfg = self.desktop_cfg;
|
||||||
|
dioxus_desktop::launch::launch_with_props_blocking(self.component, self.props, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
/// Launch a server application
|
||||||
|
pub async fn launch_server(
|
||||||
|
self,
|
||||||
|
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||||
|
) {
|
||||||
|
let addr = self.addr;
|
||||||
|
println!("Listening on {}", addr);
|
||||||
|
let cfg = self.server_cfg.build();
|
||||||
|
let server_fn_route = self.server_fn_route;
|
||||||
|
#[cfg(all(feature = "axum", not(feature = "warp"), not(feature = "salvo")))]
|
||||||
|
{
|
||||||
|
use crate::adapters::axum_adapter::{render_handler, DioxusRouterExt};
|
||||||
|
use axum::routing::get;
|
||||||
|
use tower::ServiceBuilder;
|
||||||
|
|
||||||
|
let ssr_state = SSRState::new(&cfg);
|
||||||
|
let router = axum::Router::new().register_server_fns(server_fn_route);
|
||||||
|
#[cfg(not(feature = "desktop"))]
|
||||||
|
let router = router
|
||||||
|
.serve_static_assets(cfg.assets_path)
|
||||||
|
.connect_hot_reload()
|
||||||
|
.fallback(get(render_handler).with_state((
|
||||||
|
cfg,
|
||||||
|
Arc::new(build_virtual_dom),
|
||||||
|
ssr_state,
|
||||||
|
)));
|
||||||
|
let router = router
|
||||||
|
.layer(
|
||||||
|
ServiceBuilder::new()
|
||||||
|
.layer(tower_http::compression::CompressionLayer::new().gzip(true)),
|
||||||
|
)
|
||||||
|
.into_make_service();
|
||||||
|
axum::Server::bind(&addr).serve(router).await.unwrap();
|
||||||
|
}
|
||||||
|
#[cfg(all(feature = "warp", not(feature = "axum"), not(feature = "salvo")))]
|
||||||
|
{
|
||||||
|
use warp::Filter;
|
||||||
|
// First register the server functions
|
||||||
|
let router = register_server_fns(server_fn_route);
|
||||||
|
#[cfg(not(feature = "desktop"))]
|
||||||
|
let router = {
|
||||||
|
// Serve the dist folder and the index.html file
|
||||||
|
let serve_dir = warp::fs::dir(cfg.assets_path);
|
||||||
|
|
||||||
|
router
|
||||||
|
.or(connect_hot_reload())
|
||||||
|
// Then the index route
|
||||||
|
.or(warp::path::end().and(render_ssr(cfg.clone())))
|
||||||
|
// Then the static assets
|
||||||
|
.or(serve_dir)
|
||||||
|
// Then all other routes
|
||||||
|
.or(render_ssr(cfg))
|
||||||
|
};
|
||||||
|
warp::serve(router.boxed().with(warp::filters::compression::gzip()))
|
||||||
|
.run(addr)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
#[cfg(all(feature = "salvo", not(feature = "axum"), not(feature = "warp")))]
|
||||||
|
{
|
||||||
|
use crate::adapters::salvo_adapter::{DioxusRouterExt, SSRHandler};
|
||||||
|
use salvo::conn::Listener;
|
||||||
|
let router = salvo::Router::new().register_server_fns(server_fn_route);
|
||||||
|
#[cfg(not(feature = "desktop"))]
|
||||||
|
let router = router
|
||||||
|
.serve_static_assets(cfg.assets_path)
|
||||||
|
.connect_hot_reload()
|
||||||
|
.push(salvo::Router::with_path("/<**any_path>").get(SSRHandler::new(cfg)));
|
||||||
|
let router = router.hoop(
|
||||||
|
salvo::compression::Compression::new()
|
||||||
|
.enable_gzip(salvo::prelude::CompressionLevel::Default),
|
||||||
|
);
|
||||||
|
salvo::Server::new(salvo::conn::tcp::TcpListener::new(addr).bind().await)
|
||||||
|
.serve(router)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,232 +1,35 @@
|
|||||||
//! Launch helper macros for fullstack apps
|
//! This module contains the `launch` function, which is the main entry point for dioxus fullstack
|
||||||
#![allow(unused)]
|
|
||||||
use crate::prelude::*;
|
|
||||||
use dioxus_lib::prelude::{
|
|
||||||
dioxus_core::{AnyProps, CrossPlatformConfig},
|
|
||||||
*,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod launch {
|
use std::any::Any;
|
||||||
use dioxus_lib::prelude::{dioxus_core::BoxedContext, Element, VirtualDom};
|
|
||||||
|
|
||||||
pub type Config = crate::Config;
|
use dioxus_lib::prelude::{Element, VirtualDom};
|
||||||
|
|
||||||
pub fn launch(
|
pub use crate::Config;
|
||||||
root: fn() -> Element,
|
|
||||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send>>,
|
/// Launch a fullstack app with the given root component, contexts, and config.
|
||||||
platform_config: Config,
|
pub fn launch(
|
||||||
) {
|
root: fn() -> Element,
|
||||||
#[cfg(feature = "ssr")]
|
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
||||||
tokio::runtime::Runtime::new()
|
platform_config: Config,
|
||||||
.unwrap()
|
) {
|
||||||
.block_on(async move {
|
let virtual_dom_factory = move || {
|
||||||
platform_config.launch_server(config).await;
|
let mut vdom = VirtualDom::new(root);
|
||||||
});
|
for context in &contexts {
|
||||||
#[cfg(not(feature = "ssr"))]
|
vdom.insert_any_root_context(context());
|
||||||
{
|
|
||||||
#[cfg(feature = "web")]
|
|
||||||
platform_config.launch_web(dom);
|
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
platform_config.launch_desktop(dom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Settings for a fullstack app.
|
|
||||||
pub struct Config {
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
server_fn_route: &'static str,
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
server_cfg: ServeConfigBuilder,
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
addr: std::net::SocketAddr,
|
|
||||||
#[cfg(feature = "web")]
|
|
||||||
web_cfg: dioxus_web::Config,
|
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
desktop_cfg: dioxus_desktop::Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::derivable_impls)]
|
|
||||||
impl Default for Config {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
#[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(),
|
|
||||||
#[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")]
|
|
||||||
pub fn addr(self, addr: impl Into<std::net::SocketAddr>) -> Self {
|
|
||||||
let addr = addr.into();
|
|
||||||
Self { addr, ..self }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the route to the server functions.
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
pub fn server_fn_route(self, server_fn_route: &'static str) -> Self {
|
|
||||||
Self {
|
|
||||||
server_fn_route,
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the incremental renderer config.
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
pub fn incremental(self, cfg: IncrementalRendererConfig) -> Self {
|
|
||||||
Self {
|
|
||||||
server_cfg: self.server_cfg.incremental(cfg),
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the server config.
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self {
|
|
||||||
Self { server_cfg, ..self }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the web config.
|
|
||||||
#[cfg(feature = "web")]
|
|
||||||
pub fn web_cfg(self, web_cfg: dioxus_web::Config) -> Self {
|
|
||||||
Self { web_cfg, ..self }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the desktop config.
|
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
pub fn desktop_cfg(self, desktop_cfg: dioxus_desktop::Config) -> Self {
|
|
||||||
Self {
|
|
||||||
desktop_cfg,
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Launch the app.
|
|
||||||
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(dioxus_config).await;
|
|
||||||
});
|
|
||||||
#[cfg(not(feature = "ssr"))]
|
|
||||||
{
|
|
||||||
#[cfg(feature = "web")]
|
|
||||||
self.launch_web(dioxus_config);
|
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
self.launch_desktop(dioxus_config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "web")]
|
|
||||||
/// Launch the web application
|
|
||||||
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::WebPlatform::launch(
|
|
||||||
// TODO: this should pull the props from the document
|
|
||||||
dioxus_config,
|
|
||||||
cfg,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "desktop")]
|
|
||||||
/// Launch the web application
|
|
||||||
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<P: AnyProps + Send + Sync + Clone>(
|
|
||||||
self,
|
|
||||||
dioxus_config: CrossPlatformConfig<P>,
|
|
||||||
) {
|
|
||||||
let addr = self.addr;
|
|
||||||
println!("Listening on {}", addr);
|
|
||||||
let cfg = self.server_cfg.build();
|
|
||||||
let server_fn_route = self.server_fn_route;
|
|
||||||
#[cfg(all(feature = "axum", not(feature = "warp"), not(feature = "salvo")))]
|
|
||||||
{
|
|
||||||
use crate::adapters::axum_adapter::{render_handler, DioxusRouterExt};
|
|
||||||
use axum::routing::get;
|
|
||||||
use tower::ServiceBuilder;
|
|
||||||
|
|
||||||
let ssr_state = SSRState::new(&cfg);
|
|
||||||
let router = axum::Router::new().register_server_fns(server_fn_route);
|
|
||||||
#[cfg(not(feature = "desktop"))]
|
|
||||||
let router = router
|
|
||||||
.serve_static_assets(cfg.assets_path)
|
|
||||||
.connect_hot_reload()
|
|
||||||
.fallback(get(render_handler).with_state((cfg, dioxus_config, ssr_state)));
|
|
||||||
let router = router
|
|
||||||
.layer(
|
|
||||||
ServiceBuilder::new()
|
|
||||||
.layer(tower_http::compression::CompressionLayer::new().gzip(true)),
|
|
||||||
)
|
|
||||||
.into_make_service();
|
|
||||||
axum::Server::bind(&addr).serve(router).await.unwrap();
|
|
||||||
}
|
|
||||||
#[cfg(all(feature = "warp", not(feature = "axum"), not(feature = "salvo")))]
|
|
||||||
{
|
|
||||||
use warp::Filter;
|
|
||||||
// First register the server functions
|
|
||||||
let router = register_server_fns(server_fn_route);
|
|
||||||
#[cfg(not(feature = "desktop"))]
|
|
||||||
let router = {
|
|
||||||
// Serve the dist folder and the index.html file
|
|
||||||
let serve_dir = warp::fs::dir(cfg.assets_path);
|
|
||||||
|
|
||||||
router
|
|
||||||
.or(connect_hot_reload())
|
|
||||||
// Then the index route
|
|
||||||
.or(warp::path::end().and(render_ssr(cfg.clone())))
|
|
||||||
// Then the static assets
|
|
||||||
.or(serve_dir)
|
|
||||||
// Then all other routes
|
|
||||||
.or(render_ssr(cfg))
|
|
||||||
};
|
|
||||||
warp::serve(router.boxed().with(warp::filters::compression::gzip()))
|
|
||||||
.run(addr)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
#[cfg(all(feature = "salvo", not(feature = "axum"), not(feature = "warp")))]
|
|
||||||
{
|
|
||||||
use crate::adapters::salvo_adapter::{DioxusRouterExt, SSRHandler};
|
|
||||||
use salvo::conn::Listener;
|
|
||||||
let router = salvo::Router::new().register_server_fns(server_fn_route);
|
|
||||||
#[cfg(not(feature = "desktop"))]
|
|
||||||
let router = router
|
|
||||||
.serve_static_assets(cfg.assets_path)
|
|
||||||
.connect_hot_reload()
|
|
||||||
.push(salvo::Router::with_path("/<**any_path>").get(SSRHandler::new(cfg)));
|
|
||||||
let router = router.hoop(
|
|
||||||
salvo::compression::Compression::new()
|
|
||||||
.enable_gzip(salvo::prelude::CompressionLevel::Default),
|
|
||||||
);
|
|
||||||
salvo::Server::new(salvo::conn::tcp::TcpListener::new(addr).bind().await)
|
|
||||||
.serve(router)
|
|
||||||
.await;
|
|
||||||
}
|
}
|
||||||
|
vdom
|
||||||
|
};
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
tokio::runtime::Runtime::new()
|
||||||
|
.unwrap()
|
||||||
|
.block_on(async move {
|
||||||
|
platform_config.launch_server(virtual_dom_factory).await;
|
||||||
|
});
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
|
{
|
||||||
|
#[cfg(feature = "web")]
|
||||||
|
platform_config.launch_web(virtual_dom_factory);
|
||||||
|
#[cfg(feature = "desktop")]
|
||||||
|
platform_config.launch_desktop(virtual_dom_factory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,11 +11,12 @@ mod html_storage;
|
|||||||
mod adapters;
|
mod adapters;
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
pub use adapters::*;
|
pub use adapters::*;
|
||||||
|
mod config;
|
||||||
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;
|
||||||
mod launch;
|
pub mod launch;
|
||||||
pub use launch::*;
|
pub use config::*;
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
mod layer;
|
mod layer;
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//! 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::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;
|
||||||
@@ -22,11 +21,11 @@ enum SsrRendererPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SsrRendererPool {
|
impl SsrRendererPool {
|
||||||
async fn render_to<P: AnyProps + Clone + Send + Sync + 'static>(
|
async fn render_to(
|
||||||
&self,
|
&self,
|
||||||
cfg: &ServeConfig,
|
cfg: &ServeConfig,
|
||||||
route: String,
|
route: String,
|
||||||
dioxus_config: CrossPlatformConfig<P>,
|
virtual_dom_factory: impl FnOnce() -> VirtualDom + Send + Sync + 'static,
|
||||||
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 {
|
||||||
@@ -45,7 +44,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 = dioxus_config.build_vdom();
|
let mut vdom = virtual_dom_factory();
|
||||||
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();
|
||||||
@@ -112,7 +111,7 @@ impl SsrRendererPool {
|
|||||||
match renderer
|
match renderer
|
||||||
.render(
|
.render(
|
||||||
route,
|
route,
|
||||||
dioxus_config,
|
virtual_dom_factory,
|
||||||
&mut *to,
|
&mut *to,
|
||||||
|vdom| {
|
|vdom| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
@@ -192,11 +191,11 @@ impl SSRState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Render the application to HTML.
|
/// Render the application to HTML.
|
||||||
pub fn render<'a, P: AnyProps + Clone + Send + Sync>(
|
pub fn render<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
route: String,
|
route: String,
|
||||||
cfg: &'a ServeConfig,
|
cfg: &'a ServeConfig,
|
||||||
dioxus_config: CrossPlatformConfig<P>,
|
virtual_dom_factory: impl FnOnce() -> VirtualDom + Send + Sync + 'static,
|
||||||
server_context: &'a DioxusServerContext,
|
server_context: &'a DioxusServerContext,
|
||||||
) -> impl std::future::Future<
|
) -> impl std::future::Future<
|
||||||
Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
|
Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
|
||||||
@@ -207,7 +206,7 @@ impl SSRState {
|
|||||||
|
|
||||||
let (freshness, html) = self
|
let (freshness, html) = self
|
||||||
.renderers
|
.renderers
|
||||||
.render_to(cfg, route, dioxus_config, server_context)
|
.render_to(cfg, route, virtual_dom_factory, server_context)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(RenderResponse { html, freshness })
|
Ok(RenderResponse { html, freshness })
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ impl IncrementalRenderer {
|
|||||||
pub async fn render<R: WrapBody + Send + Sync>(
|
pub async fn render<R: WrapBody + Send + Sync>(
|
||||||
&mut self,
|
&mut self,
|
||||||
route: String,
|
route: String,
|
||||||
virtual_dom: VirtualDom,
|
virtual_dom_factory: impl FnOnce() -> VirtualDom,
|
||||||
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,
|
||||||
@@ -181,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, virtual_dom, output, rebuild_with, renderer)
|
.render_and_cache(route, virtual_dom_factory(), output, rebuild_with, renderer)
|
||||||
.await?;
|
.await?;
|
||||||
tracing::trace!("cache miss");
|
tracing::trace!("cache miss");
|
||||||
Ok(freshness)
|
Ok(freshness)
|
||||||
|
|||||||
Reference in new issue
Block a user