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
|
||||
/// 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);
|
||||
|
||||
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.
|
||||
pub fn launch(
|
||||
root: fn() -> Element,
|
||||
|
||||
@@ -63,7 +63,8 @@ use axum::{
|
||||
routing::{get, post},
|
||||
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 std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
@@ -216,11 +217,11 @@ pub trait DioxusRouterExt<S> {
|
||||
/// todo!()
|
||||
/// }
|
||||
/// ```
|
||||
fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||
fn serve_dioxus_application(
|
||||
self,
|
||||
server_fn_route: &'static str,
|
||||
cfg: impl Into<ServeConfig>,
|
||||
dioxus_config: CrossPlatformConfig<P>,
|
||||
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
@@ -315,11 +316,11 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
fn serve_dioxus_application<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||
fn serve_dioxus_application(
|
||||
self,
|
||||
server_fn_route: &'static str,
|
||||
cfg: impl Into<ServeConfig>,
|
||||
dioxus_config: CrossPlatformConfig<P>,
|
||||
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
let cfg = cfg.into();
|
||||
let ssr_state = SSRState::new(&cfg);
|
||||
@@ -328,7 +329,7 @@ where
|
||||
self.serve_static_assets(cfg.assets_path)
|
||||
.connect_hot_reload()
|
||||
.register_server_fns(server_fn_route)
|
||||
.fallback(get(render_handler).with_state((cfg, dioxus_config, ssr_state)))
|
||||
.fallback(get(render_handler).with_state((cfg, Arc::new(build_virtual_dom), ssr_state)))
|
||||
}
|
||||
|
||||
fn connect_hot_reload(self) -> Self {
|
||||
@@ -418,15 +419,12 @@ fn apply_request_parts_to_response<B>(
|
||||
/// .unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn render_handler_with_context<
|
||||
P: AnyProps + Clone + Send + Sync + 'static,
|
||||
F: FnMut(&mut DioxusServerContext),
|
||||
>(
|
||||
State((mut inject_context, cfg, ssr_state, dioxus_config)): State<(
|
||||
pub async fn render_handler_with_context<F: FnMut(&mut DioxusServerContext)>(
|
||||
State((mut inject_context, cfg, ssr_state, virtual_dom_factory)): State<(
|
||||
F,
|
||||
ServeConfig,
|
||||
SSRState,
|
||||
CrossPlatformConfig<P>,
|
||||
Arc<dyn Fn() -> VirtualDom + Send + Sync>,
|
||||
)>,
|
||||
request: Request<Body>,
|
||||
) -> impl IntoResponse {
|
||||
@@ -437,7 +435,7 @@ pub async fn render_handler_with_context<
|
||||
inject_context(&mut server_context);
|
||||
|
||||
match ssr_state
|
||||
.render(url, &cfg, dioxus_config, &server_context)
|
||||
.render(url, &cfg, move || virtual_dom_factory(), &server_context)
|
||||
.await
|
||||
{
|
||||
Ok(rendered) => {
|
||||
@@ -456,12 +454,16 @@ pub async fn render_handler_with_context<
|
||||
}
|
||||
|
||||
/// SSR renderer handler for Axum
|
||||
pub async fn render_handler<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||
State((cfg, dioxus_config, ssr_state)): State<(ServeConfig, CrossPlatformConfig<P>, SSRState)>,
|
||||
pub async fn render_handler(
|
||||
State((cfg, virtual_dom_factory, ssr_state)): State<(
|
||||
ServeConfig,
|
||||
Arc<dyn Fn() -> VirtualDom + Send + Sync>,
|
||||
SSRState,
|
||||
)>,
|
||||
request: Request<Body>,
|
||||
) -> impl IntoResponse {
|
||||
render_handler_with_context(
|
||||
State((|_: &mut _| (), cfg, ssr_state, dioxus_config)),
|
||||
State((|_: &mut _| (), cfg, ssr_state, virtual_dom_factory)),
|
||||
request,
|
||||
)
|
||||
.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
|
||||
#![allow(unused)]
|
||||
use crate::prelude::*;
|
||||
use dioxus_lib::prelude::{
|
||||
dioxus_core::{AnyProps, CrossPlatformConfig},
|
||||
*,
|
||||
};
|
||||
//! This module contains the `launch` function, which is the main entry point for dioxus fullstack
|
||||
|
||||
pub mod launch {
|
||||
use dioxus_lib::prelude::{dioxus_core::BoxedContext, Element, VirtualDom};
|
||||
use std::any::Any;
|
||||
|
||||
pub type Config = crate::Config;
|
||||
use dioxus_lib::prelude::{Element, VirtualDom};
|
||||
|
||||
pub fn launch(
|
||||
root: fn() -> Element,
|
||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send>>,
|
||||
platform_config: 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(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;
|
||||
pub use crate::Config;
|
||||
|
||||
/// Launch a fullstack app with the given root component, contexts, and config.
|
||||
pub fn launch(
|
||||
root: fn() -> Element,
|
||||
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
|
||||
platform_config: Config,
|
||||
) {
|
||||
let virtual_dom_factory = move || {
|
||||
let mut vdom = VirtualDom::new(root);
|
||||
for context in &contexts {
|
||||
vdom.insert_any_root_context(context());
|
||||
}
|
||||
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;
|
||||
#[cfg(feature = "ssr")]
|
||||
pub use adapters::*;
|
||||
mod config;
|
||||
mod hooks;
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))]
|
||||
mod hot_reload;
|
||||
mod launch;
|
||||
pub use launch::*;
|
||||
pub mod launch;
|
||||
pub use config::*;
|
||||
#[cfg(feature = "ssr")]
|
||||
mod layer;
|
||||
#[cfg(feature = "ssr")]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//! A shared pool of renderers for efficient server side rendering.
|
||||
use crate::render::dioxus_core::AnyProps;
|
||||
use crate::render::dioxus_core::CrossPlatformConfig;
|
||||
use crate::render::dioxus_core::NoOpMutations;
|
||||
use crate::server_context::SERVER_CONTEXT;
|
||||
use dioxus_lib::prelude::VirtualDom;
|
||||
@@ -22,11 +21,11 @@ enum SsrRendererPool {
|
||||
}
|
||||
|
||||
impl SsrRendererPool {
|
||||
async fn render_to<P: AnyProps + Clone + Send + Sync + 'static>(
|
||||
async fn render_to(
|
||||
&self,
|
||||
cfg: &ServeConfig,
|
||||
route: String,
|
||||
dioxus_config: CrossPlatformConfig<P>,
|
||||
virtual_dom_factory: impl FnOnce() -> VirtualDom + Send + Sync + 'static,
|
||||
server_context: &DioxusServerContext,
|
||||
) -> Result<(RenderFreshness, String), dioxus_ssr::incremental::IncrementalRendererError> {
|
||||
let wrapper = FullstackRenderer {
|
||||
@@ -45,7 +44,7 @@ impl SsrRendererPool {
|
||||
tokio::runtime::Runtime::new()
|
||||
.expect("couldn't spawn runtime")
|
||||
.block_on(async move {
|
||||
let mut vdom = dioxus_config.build_vdom();
|
||||
let mut vdom = virtual_dom_factory();
|
||||
vdom.in_runtime(|| {
|
||||
// Make sure the evaluator is initialized
|
||||
dioxus_ssr::eval::init_eval();
|
||||
@@ -112,7 +111,7 @@ impl SsrRendererPool {
|
||||
match renderer
|
||||
.render(
|
||||
route,
|
||||
dioxus_config,
|
||||
virtual_dom_factory,
|
||||
&mut *to,
|
||||
|vdom| {
|
||||
Box::pin(async move {
|
||||
@@ -192,11 +191,11 @@ impl SSRState {
|
||||
}
|
||||
|
||||
/// Render the application to HTML.
|
||||
pub fn render<'a, P: AnyProps + Clone + Send + Sync>(
|
||||
pub fn render<'a>(
|
||||
&'a self,
|
||||
route: String,
|
||||
cfg: &'a ServeConfig,
|
||||
dioxus_config: CrossPlatformConfig<P>,
|
||||
virtual_dom_factory: impl FnOnce() -> VirtualDom + Send + Sync + 'static,
|
||||
server_context: &'a DioxusServerContext,
|
||||
) -> impl std::future::Future<
|
||||
Output = Result<RenderResponse, dioxus_ssr::incremental::IncrementalRendererError>,
|
||||
@@ -207,7 +206,7 @@ impl SSRState {
|
||||
|
||||
let (freshness, html) = self
|
||||
.renderers
|
||||
.render_to(cfg, route, dioxus_config, server_context)
|
||||
.render_to(cfg, route, virtual_dom_factory, server_context)
|
||||
.await?;
|
||||
|
||||
Ok(RenderResponse { html, freshness })
|
||||
|
||||
@@ -170,7 +170,7 @@ impl IncrementalRenderer {
|
||||
pub async fn render<R: WrapBody + Send + Sync>(
|
||||
&mut self,
|
||||
route: String,
|
||||
virtual_dom: VirtualDom,
|
||||
virtual_dom_factory: impl FnOnce() -> VirtualDom,
|
||||
output: &mut (impl AsyncWrite + Unpin + std::marker::Send),
|
||||
rebuild_with: impl FnOnce(&mut VirtualDom) -> Pin<Box<dyn Future<Output = ()> + '_>>,
|
||||
renderer: &R,
|
||||
@@ -181,7 +181,7 @@ impl IncrementalRenderer {
|
||||
} else {
|
||||
// if not, create it
|
||||
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?;
|
||||
tracing::trace!("cache miss");
|
||||
Ok(freshness)
|
||||
|
||||
Reference in new issue
Block a user