mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-12-25 03:53:08 +00:00
218 lines
7.4 KiB
Rust
218 lines
7.4 KiB
Rust
//! Launch helper macros for fullstack apps
|
|
#![allow(unused)]
|
|
use crate::prelude::*;
|
|
use dioxus::prelude::*;
|
|
#[cfg(feature = "router")]
|
|
use dioxus_router::prelude::*;
|
|
|
|
/// A builder for a fullstack app.
|
|
pub struct LaunchBuilder<Props: Clone> {
|
|
component: Component<Props>,
|
|
#[cfg(not(feature = "ssr"))]
|
|
props: Props,
|
|
#[cfg(feature = "ssr")]
|
|
server_fn_route: &'static str,
|
|
#[cfg(feature = "ssr")]
|
|
server_cfg: ServeConfigBuilder<Props>,
|
|
#[cfg(feature = "ssr")]
|
|
addr: std::net::SocketAddr,
|
|
#[cfg(feature = "web")]
|
|
web_cfg: dioxus_web::Config,
|
|
#[cfg(feature = "desktop")]
|
|
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,
|
|
{
|
|
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),
|
|
#[cfg(feature = "web")]
|
|
web_cfg: dioxus_web::Config::default(),
|
|
#[cfg(feature = "desktop")]
|
|
desktop_cfg: dioxus_desktop::Config::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<Props>) -> 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) {
|
|
#[cfg(feature = "ssr")]
|
|
tokio::runtime::Runtime::new()
|
|
.unwrap()
|
|
.block_on(async move {
|
|
self.launch_server().await;
|
|
});
|
|
#[cfg(not(feature = "ssr"))]
|
|
{
|
|
#[cfg(feature = "web")]
|
|
self.launch_web();
|
|
#[cfg(feature = "desktop")]
|
|
self.launch_desktop();
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "web")]
|
|
fn launch_web(self) {
|
|
let cfg = self.web_cfg.hydrate(true);
|
|
dioxus_web::launch_with_props(self.component, get_root_props_from_document().unwrap(), cfg);
|
|
}
|
|
|
|
#[cfg(feature = "desktop")]
|
|
fn launch_desktop(self) {
|
|
let cfg = self.desktop_cfg;
|
|
dioxus_desktop::launch_with_props(self.component, self.props, cfg);
|
|
}
|
|
|
|
/// Launch a server with the given configuration
|
|
/// This will use the routing integration of the currently enabled integration feature
|
|
#[cfg(feature = "ssr")]
|
|
async fn launch_server(self) {
|
|
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, 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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)
|
|
}
|
|
}
|