Simplify the launch builder (#2967)

* improve documentation for the fullstack server context

* Add a section about axum integration to the crate root docs

* make serve_dioxus_application accept the cfg builder directly

* remove unused server_fn module

* improve fullstack config docs

* improve documentation for the server function macro

* fix axum router extension link

* Fix doc tests

* Fix launch builder

* Simplify the launch builder

* don't re-export launch in the prelude

* refactor fullstack launch

* Fix fullstack launch builder

* Update static generation with the new builder api

* fix some formatting/overly broad launch replacements

* fix custom menu example

* fix fullstack/static generation examples

* Fix static generation launch

* A few small formatting fixes

* Fix a few doc tests

* implement LaunchConfig for serve configs

* fix fullstack launch with separate web and server launch methods

* fix check with all features

* dont expose inner core module

* clippy and check

* fix readme

---------

Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
Evan Almloff 2024-10-10 18:00:58 -05:00 committed by GitHub
parent 2d7bef44e8
commit 20d146d9bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
126 changed files with 618 additions and 989 deletions

View file

@ -15,7 +15,7 @@ mod components {
mod api;
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
head::Link {
rel: "stylesheet",

View file

@ -12,7 +12,7 @@ use dioxus::desktop::{Config, WindowBuilder};
use dioxus::prelude::*;
fn main() {
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(Config::new().with_window(WindowBuilder::new().with_resizable(true)))
.launch(app)
}

View file

@ -17,7 +17,7 @@ fn main() {
#[cfg(feature = "server")]
tracing_subscriber::fmt::init();
launch(|| rsx! { Router::<Route> {} });
dioxus::launch(|| rsx! { Router::<Route> {} });
}
#[derive(Clone, Routable)]

View file

@ -2,7 +2,7 @@ use dioxus::prelude::*;
use wifiscanner::Wifi;
fn main() {
launch(app)
dioxus::launch(app)
}
fn perform_scan() -> Status {

View file

@ -9,7 +9,7 @@ use std::{collections::VecDeque, fmt::Debug, rc::Rc};
const STYLE: &str = asset!("./examples/assets/events.css");
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@ use async_std::task::sleep;
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -15,7 +15,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/calculator.css");
fn main() {
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(desktop!({
use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
Config::new().with_window(

View file

@ -13,7 +13,7 @@ use dioxus::html::MouseEvent;
use dioxus::prelude::*;
fn main() {
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(
Config::new().with_window(
WindowBuilder::new()

View file

@ -8,7 +8,7 @@ use web_time::Instant;
const STYLE: &str = asset!("./examples/assets/clock.css");
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/roulette.css");
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/counter.css");
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -12,7 +12,7 @@
use dioxus::prelude::*;
fn main() {
LaunchBuilder::new()
dioxus::LaunchBuilder::new()
.with_cfg(desktop!({
use dioxus::desktop::{LogicalSize, WindowBuilder};
dioxus::desktop::Config::default()

View file

@ -14,7 +14,7 @@ static ASSET_PATH: &str = "examples/assets/logo.png";
static ASSET_PATH: &str = asset!("examples/assets/logo.png".format(ImageType::Avif));
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -4,7 +4,7 @@
use dioxus::prelude::*;
fn main() {
LaunchBuilder::new()
dioxus::LaunchBuilder::new()
.with_cfg(
dioxus::desktop::Config::new().with_custom_index(
r#"

View file

@ -28,7 +28,7 @@ fn main() {
let config = dioxus::desktop::Config::new().with_menu(menu);
// Launch the app with the custom menu
LaunchBuilder::new().with_cfg(config).launch(app)
dioxus::LaunchBuilder::new().with_cfg(config).launch(app)
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@ use dioxus::prelude::*;
use std::collections::HashMap;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -10,7 +10,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/custom_assets.css");
fn main() {
launch_desktop(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@
use dioxus::prelude::*;
fn main() {
launch(|| rsx! { Router::<Route> {} });
dioxus::launch(|| rsx! { Router::<Route> {} });
}
/// You can use an ErrorBoundary to catch errors in children and display a warning

View file

@ -7,7 +7,7 @@ use async_std::task::sleep;
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@ use dioxus::{html::HasFileData, prelude::dioxus_elements::FileEngine};
const STYLE: &str = asset!("./examples/assets/file_upload.css");
fn main() {
launch(app);
dioxus::launch(app);
}
struct UploadedFile {

View file

@ -12,7 +12,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/flat_router.css");
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
head::Link { rel: "stylesheet", href: STYLE }
Router::<Route> {}

View file

@ -7,7 +7,7 @@ use dioxus::prelude::*;
use std::collections::HashMap;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@ fn main() {
// Set the url of the server where server functions are hosted.
#[cfg(not(feature = "server"))]
dioxus::fullstack::prelude::server_fn::client::set_server_url("http://127.0.0.1:8080");
launch(app);
dioxus::launch(app);
}
pub fn app() -> Element {

View file

@ -50,5 +50,5 @@ fn main() {
#[cfg(feature = "server")]
tracing_subscriber::fmt::init();
launch(app);
dioxus::launch(app);
}

View file

@ -7,7 +7,7 @@
use dioxus::prelude::*;
fn main() {
LaunchBuilder::fullstack()
dioxus::LaunchBuilder::new()
.with_cfg(server_only!(ServeConfig::builder().incremental(
IncrementalRendererConfig::default()
.invalidate_after(std::time::Duration::from_secs(120)),

View file

@ -37,5 +37,5 @@ pub async fn test_stream() -> Result<TextStream, ServerFnError> {
}
fn main() {
launch(app)
dioxus::launch(app)
}

View file

@ -7,7 +7,7 @@ use async_std::task::sleep;
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -7,7 +7,7 @@ use dioxus::prelude::*;
use std::fmt::Display;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -13,7 +13,7 @@ static COUNT: GlobalSignal<i32> = Signal::global(|| 0);
static DOUBLED_COUNT: GlobalMemo<i32> = Memo::global(|| COUNT() * 2);
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -19,7 +19,7 @@ use dioxus::prelude::*;
use serde::{Deserialize, Serialize};
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
Router::<Route> {}
}

View file

@ -12,7 +12,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -13,7 +13,7 @@ use dioxus::desktop::Config;
use dioxus::prelude::*;
fn main() {
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(Config::new().with_prerendered({
// We build the dom a first time, then pre-render it to HTML
let pre_rendered_dom = VirtualDom::prebuilt(app);

View file

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use serde_json::{json, Error};
fn main() {
launch(app)
dioxus::launch(app)
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/links.css");
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -9,7 +9,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -6,7 +6,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -4,7 +4,7 @@ use dioxus::prelude::*;
fn main() {
tracing_subscriber::fmt::init();
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -50,7 +50,7 @@ pub fn main() -> Result<()> {
// Right now we're going through dioxus-desktop but we'd like to go through dioxus-mobile
// That will seed the index.html with some fixes that prevent the page from scrolling/zooming etc
LaunchBuilder::mobile()
dioxus::LaunchBuilder::mobile()
.with_cfg(
// Note that we have to disable the viewport goofiness of the browser.
// Dioxus_mobile should do this for us

View file

@ -7,7 +7,7 @@
use dioxus::prelude::*;
fn main() {
launch_desktop(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
fn app() -> Element {

View file

@ -7,7 +7,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -6,7 +6,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,9 @@ use dioxus::desktop::{
use dioxus::prelude::*;
fn main() {
LaunchBuilder::desktop().with_cfg(make_config()).launch(app);
dioxus::LaunchBuilder::desktop()
.with_cfg(make_config())
.launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@ use dioxus::prelude::*;
use std::rc::Rc;
fn main() {
launch_desktop(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@ fn main() {
wasm_logger::init(wasm_logger::Config::default());
console_error_panic_hook::set_once();
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -14,7 +14,7 @@
use dioxus::prelude::*;
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
Router::<Route> {}
}

View file

@ -9,7 +9,7 @@ use std::rc::Rc;
use dioxus::{html::geometry::euclid::Rect, prelude::*};
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -8,7 +8,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -10,7 +10,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/radio.css");
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -8,7 +8,7 @@ use dioxus::prelude::*;
use dioxus_elements::geometry::euclid::Size2D;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -11,7 +11,7 @@ use dioxus::prelude::*;
const STYLE: &str = asset!("./examples/assets/router.css");
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
head::Link { rel: "stylesheet", href: STYLE }
Router::<Route> {}

View file

@ -15,7 +15,7 @@ enum Route {
}
fn main() {
launch(App);
dioxus::launch(App);
}
#[component]

View file

@ -39,7 +39,7 @@
//! - Allow top-level fragments
fn main() {
launch(app)
dioxus::launch(app)
}
use core::{fmt, str::FromStr};

View file

@ -8,7 +8,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -9,7 +9,7 @@ use dioxus::desktop::use_global_shortcut;
use dioxus::prelude::*;
fn main() {
launch_desktop(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
fn app() -> Element {

View file

@ -3,7 +3,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -10,7 +10,7 @@ use async_std::task::sleep;
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -3,9 +3,9 @@
use dioxus::prelude::*;
fn main() {
// Launch the router, using our `Route` component as the generic type
// launch the router, using our `Route` component as the generic type
// This will automatically boot the app to "/" unless otherwise specified
launch(|| rsx! { Router::<Route> {} });
dioxus::launch(|| rsx! { Router::<Route> {} });
}
/// By default, the Routable derive will use the name of the variant as the route

View file

@ -6,7 +6,7 @@ use dioxus::prelude::*;
// Generate all routes and output them to the static path
fn main() {
LaunchBuilder::new()
dioxus::LaunchBuilder::new()
.with_cfg(dioxus::static_site_generation::Config::new().github_pages())
.launch(|| {
rsx! {

View file

@ -5,7 +5,7 @@ use dioxus::prelude::*;
// Generate all routes and output them to the static path
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
Router::<Route> {}
}

View file

@ -3,7 +3,7 @@ use dioxus::prelude::*;
// Generate all routes and output them to the static path
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@ use dioxus::prelude::*;
use futures_util::{future, stream, Stream, StreamExt};
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -15,7 +15,7 @@ use dioxus::desktop::{Config, LogicalSize, WindowBuilder};
use dioxus::prelude::*;
fn main() {
LaunchBuilder::new()
dioxus::LaunchBuilder::new()
.with_cfg(desktop! {
Config::new().with_window(
WindowBuilder::new()

View file

@ -10,7 +10,7 @@ use dioxus::prelude::*;
use rand::{thread_rng, Rng};
fn main() {
launch(|| {
dioxus::launch(|| {
rsx! {
div { user_select: "none", webkit_user_select: "none", margin_left: "10%", margin_right: "10%",
h1 { "Click die to generate a new value" }

View file

@ -5,7 +5,7 @@ use dioxus::prelude::*;
const _STYLE: &str = asset!("public/tailwind.css");
fn main() {
launch(app);
dioxus::launch(app);
}
pub fn app() -> Element {

View file

@ -4,7 +4,7 @@ use dioxus::prelude::*;
fn main() {
tracing_subscriber::fmt::init();
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -6,7 +6,7 @@ use std::collections::HashMap;
const STYLE: &str = asset!("./examples/assets/todomvc.css");
fn main() {
launch(app);
dioxus::launch(app);
}
#[derive(PartialEq, Eq, Clone, Copy)]

View file

@ -16,13 +16,13 @@ fn main() {
// For the sake of this example, we will download the video file if it doesn't exist
ensure_video_is_loaded();
launch_desktop(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
fn app() -> Element {
// Any request to /videos will be handled by this handler
use_asset_handler("videos", move |request, responder| {
// Using dioxus::spawn works, but is slower than a dedicated thread
// Using spawn works, but is slower than a dedicated thread
tokio::task::spawn(async move {
let video_file = PathBuf::from(VIDEO_PATH);
let mut file = tokio::fs::File::open(&video_file).await.unwrap();

View file

@ -4,7 +4,7 @@ use dioxus::prelude::*;
use serde::{Deserialize, Serialize};
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -7,7 +7,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -13,7 +13,7 @@ use dioxus::desktop::{window, Config, WindowBuilder};
use dioxus::prelude::*;
fn main() {
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(
Config::new().with_window(
WindowBuilder::new()

View file

@ -12,7 +12,7 @@ use dioxus::desktop::{Config, WindowCloseBehaviour};
use dioxus::prelude::*;
fn main() {
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(Config::new().with_close_behaviour(WindowCloseBehaviour::CloseWindow))
.launch(app)
}

View file

@ -5,7 +5,7 @@
use dioxus::prelude::*;
fn main() {
launch_desktop(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
fn app() -> Element {

View file

@ -5,7 +5,7 @@
use dioxus::prelude::*;
fn main() {
launch(app);
dioxus::launch(app);
}
fn app() -> Element {

View file

@ -8,7 +8,7 @@ use std::{
use tokio::time::sleep;
fn main() {
LaunchBuilder::desktop().launch(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
struct WindowPreferences {

View file

@ -8,7 +8,7 @@ use std::{
use tokio::time::sleep;
fn main() {
LaunchBuilder::desktop().launch(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
struct WindowPreferences {

View file

@ -8,7 +8,7 @@ use std::{
use tokio::time::sleep;
fn main() {
LaunchBuilder::desktop().launch(app);
dioxus::LaunchBuilder::desktop().launch(app);
}
struct WindowPreferences {

View file

@ -150,6 +150,49 @@ impl BuildRequest {
}
}
#[derive(Debug, Clone, Default)]
pub(crate) struct OpenArguments {
fullstack_address: Option<SocketAddr>,
devserver_addr: Option<SocketAddr>,
always_on_top: Option<bool>,
workspace: PathBuf,
asset_root: PathBuf,
app_title: String,
out_dir: PathBuf,
serve: bool,
}
impl OpenArguments {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
serve: &ServeArguments,
fullstack_address: Option<SocketAddr>,
dioxus_crate: &DioxusCrate,
) -> Self {
Self {
devserver_addr: Some(serve.address.address()),
always_on_top: Some(serve.always_on_top.unwrap_or(true)),
serve: true,
fullstack_address,
workspace: dioxus_crate.workspace_dir().to_path_buf(),
asset_root: dioxus_crate.asset_dir().to_path_buf(),
app_title: dioxus_crate.dioxus_config.application.name.clone(),
out_dir: dioxus_crate.out_dir().to_path_buf(),
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn new_for_static_generation_build(dioxus_crate: &DioxusCrate) -> Self {
Self {
workspace: dioxus_crate.workspace_dir().to_path_buf(),
asset_root: dioxus_crate.asset_dir().to_path_buf(),
app_title: dioxus_crate.dioxus_config.application.name.clone(),
out_dir: dioxus_crate.out_dir().to_path_buf(),
..Default::default()
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct BuildResult {
pub executable: PathBuf,
@ -158,20 +201,12 @@ pub(crate) struct BuildResult {
impl BuildResult {
/// Open the executable if this is a native build
#[allow(clippy::too_many_arguments)]
pub fn open(
&self,
serve: &ServeArguments,
fullstack_address: Option<SocketAddr>,
workspace: &std::path::Path,
asset_root: &std::path::Path,
devserver_addr: SocketAddr,
app_title: String,
out_dir: PathBuf,
) -> std::io::Result<Option<Child>> {
pub fn open(&self, arguments: OpenArguments) -> std::io::Result<Option<Child>> {
match self.target_platform {
TargetPlatform::Web => {
tracing::info!(dx_src = ?TraceSrc::Dev, "Serving web app on http://{} 🎉", serve.address.address());
if let Some(address) = arguments.fullstack_address {
tracing::info!(dx_src = ?TraceSrc::Dev, "Serving web app on http://{} 🎉", address);
}
return Ok(None);
}
TargetPlatform::Desktop => {
@ -181,7 +216,7 @@ impl BuildResult {
// shut this up for now - the web app will take priority in logging
}
TargetPlatform::Liveview => {
if let Some(fullstack_address) = fullstack_address {
if let Some(fullstack_address) = arguments.fullstack_address {
tracing::info!(
dx_src = ?TraceSrc::Dev,
"Launching liveview server on http://{:?} 🎉",
@ -191,7 +226,9 @@ impl BuildResult {
}
}
if arguments.serve {
tracing::info!(dx_src = ?TraceSrc::Dev, "Press [o] to open the app manually.");
}
let executable = self.executable.canonicalize()?;
let mut cmd = Command::new(executable);
@ -199,29 +236,36 @@ impl BuildResult {
// Set the env vars that the clients will expect
// These need to be stable within a release version (ie 0.6.0)
cmd.env(dioxus_cli_config::CLI_ENABLED_ENV, "true");
if let Some(addr) = fullstack_address {
if let Some(addr) = arguments.fullstack_address {
cmd.env(dioxus_cli_config::SERVER_IP_ENV, addr.ip().to_string());
cmd.env(dioxus_cli_config::SERVER_PORT_ENV, addr.port().to_string());
}
if let Some(always_on_top) = arguments.always_on_top {
cmd.env(
dioxus_cli_config::ALWAYS_ON_TOP_ENV,
serve.always_on_top.unwrap_or(true).to_string(),
always_on_top.to_string(),
);
}
cmd.env(
dioxus_cli_config::ASSET_ROOT_ENV,
asset_root.display().to_string(),
arguments.asset_root.display().to_string(),
);
if let Some(devserver_addr) = arguments.devserver_addr {
cmd.env(
dioxus_cli_config::DEVSERVER_RAW_ADDR_ENV,
devserver_addr.to_string(),
);
cmd.env(dioxus_cli_config::APP_TITLE_ENV, app_title);
cmd.env(dioxus_cli_config::OUT_DIR, out_dir.display().to_string());
}
cmd.env(dioxus_cli_config::APP_TITLE_ENV, arguments.app_title);
cmd.env(
dioxus_cli_config::OUT_DIR,
arguments.out_dir.display().to_string(),
);
cmd.stderr(Stdio::piped())
.stdout(Stdio::piped())
.kill_on_drop(true)
.current_dir(workspace);
.current_dir(arguments.workspace);
Ok(Some(cmd.spawn()?))
}

View file

@ -1,6 +1,6 @@
use std::str::FromStr;
use crate::config::Platform;
use crate::{builder::OpenArguments, config::Platform};
use anyhow::Context;
use crate::{
@ -115,7 +115,20 @@ impl Build {
pub async fn build(&mut self, dioxus_crate: &mut DioxusCrate) -> Result<()> {
self.resolve(dioxus_crate)?;
let build_requests = BuildRequest::create(false, dioxus_crate, self.clone())?;
BuildRequest::build_all_parallel(build_requests).await?;
let builds = BuildRequest::build_all_parallel(build_requests).await?;
// If this is a static generation build, building involves running the server to generate static files
if self.platform.unwrap() == Platform::StaticGeneration {
println!("Building static site...");
for build in builds {
if let Some(mut result) =
build.open(OpenArguments::new_for_static_generation_build(dioxus_crate))?
{
result.wait().await?;
}
}
println!("Static site built!");
}
Ok(())
}

View file

@ -1,6 +1,7 @@
use std::future::{poll_fn, Future, IntoFuture};
use std::task::Poll;
use crate::builder::OpenArguments;
use crate::cli::serve::Serve;
use crate::dioxus_crate::DioxusCrate;
use crate::tracer::CLILogControl;
@ -156,23 +157,14 @@ pub async fn serve_all(
builder.children.clear();
}
let asset_dir = dioxus_crate
.dioxus_config
.application
.asset_dir
.canonicalize()
.unwrap_or(std::path::PathBuf::from("./assets"));
// If we have a build result, open it
for build_result in results.iter() {
let child = build_result.open(
OpenArguments::new(
&serve.server_arguments,
server.fullstack_address(),
&dioxus_crate.workspace_dir(),
&asset_dir,
server.ip,
dioxus_crate.dioxus_config.application.name.clone(),
dioxus_crate.out_dir()
&dioxus_crate
)
);
match child {
Ok(Some(child_proc)) => builder.children.push((build_result.target_platform, child_proc)),
@ -192,12 +184,12 @@ pub async fn serve_all(
server.send_reload_command().await;
},
// If the process exited *cleanly*, we can exit
// If the desktop process exited *cleanly*, we can exit
Ok(BuilderUpdate::ProcessExited { status, target_platform }) => {
// Then remove the child process
builder.children.retain(|(platform, _)| *platform != target_platform);
match status {
Ok(status) => {
match (target_platform, status) {
(TargetPlatform::Desktop, Ok(status)) => {
if status.success() {
break;
}
@ -205,7 +197,9 @@ pub async fn serve_all(
tracing::error!(dx_src = ?TraceSrc::Dev, "Application exited with status: {status}");
}
},
Err(e) => {
// Ignore the static generation platform exiting
(_ , Ok(_)) => {},
(_, Err(e)) => {
tracing::error!(dx_src = ?TraceSrc::Dev, "Application exited with error: {e}");
}
}

View file

@ -114,7 +114,7 @@ impl Server {
// If we're serving a fullstack app, we need to find a port to proxy to
let fullstack_port = if matches!(
serve.build_arguments.platform(),
Platform::Liveview | Platform::Fullstack | Platform::StaticGeneration
Platform::Liveview | Platform::Fullstack
) {
get_available_port(addr.ip())
} else {
@ -368,7 +368,7 @@ fn setup_router(
// server the dir if it's web, otherwise let the fullstack server itself handle it
match platform {
Platform::Web => {
Platform::Web | Platform::StaticGeneration => {
// Route file service to output the .wasm and assets if this is a web build
let base_path = format!(
"/{}",
@ -382,9 +382,9 @@ fn setup_router(
.trim_matches('/')
);
router = router.nest_service(&base_path, build_serve_dir(serve, config));
router = router.nest_service(&base_path, build_serve_dir(serve, config, platform));
}
Platform::Liveview | Platform::Fullstack | Platform::StaticGeneration => {
Platform::Liveview | Platform::Fullstack => {
// For fullstack and static generation, forward all requests to the server
let address = fullstack_address.unwrap();
@ -449,7 +449,11 @@ fn setup_router(
Ok(router)
}
fn build_serve_dir(serve: &Serve, cfg: &DioxusCrate) -> axum::routing::MethodRouter {
fn build_serve_dir(
serve: &Serve,
cfg: &DioxusCrate,
platform: Platform,
) -> axum::routing::MethodRouter {
static CORS_UNSAFE: (HeaderValue, HeaderValue) = (
HeaderValue::from_static("unsafe-none"),
HeaderValue::from_static("unsafe-none"),
@ -465,7 +469,11 @@ fn build_serve_dir(serve: &Serve, cfg: &DioxusCrate) -> axum::routing::MethodRou
false => CORS_UNSAFE.clone(),
};
let out_dir = cfg.out_dir();
let out_dir = match platform {
// Static generation only serves files from the public directory
Platform::StaticGeneration => cfg.out_dir().join("public"),
_ => cfg.out_dir(),
};
let index_on_404 = cfg.dioxus_config.web.watcher.index_on_404;
get_service(
@ -479,7 +487,7 @@ fn build_serve_dir(serve: &Serve, cfg: &DioxusCrate) -> axum::routing::MethodRou
let out_dir = out_dir.clone();
move |response| async move { Ok(no_cache(index_on_404, &out_dir, response)) }
})
.service(ServeDir::new(out_dir)),
.service(ServeDir::new(&out_dir)),
)
.handle_error(|error: Infallible| async move {
(
@ -500,7 +508,18 @@ fn no_cache(
// If there's a 404 and we're supposed to index on 404, upgrade that failed request to the index.html
// We might want to isnert a header here saying we *did* that but oh well
if response.status() == StatusCode::NOT_FOUND && index_on_404 {
let body = Body::from(std::fs::read_to_string(out_dir.join("index.html")).unwrap());
// First try to find a 404.html or 404/index.html file
let out_dir_404_html = out_dir.join("404.html");
let out_dir_404_index_html = out_dir.join("404").join("index.html");
let path = if out_dir_404_html.exists() {
out_dir_404_html
} else if out_dir_404_index_html.exists() {
out_dir_404_index_html
} else {
// If we can't find a 404.html or 404/index.html, just use the index.html
out_dir.join("index.html")
};
let body = Body::from(std::fs::read_to_string(path).unwrap());
response = Response::builder()
.status(StatusCode::OK)

View file

@ -0,0 +1,8 @@
//! This module contains utilities renderers use to integrate with the launch function.
/// A marker trait for platform configs. We use this marker to
/// make sure that the user doesn't accidentally pass in a config
/// builder instead of the config
pub trait LaunchConfig: 'static {}
impl LaunchConfig for () {}

View file

@ -12,6 +12,7 @@ mod events;
mod fragment;
mod generational_box;
mod global_context;
mod launch;
mod mutations;
mod nodes;
mod properties;
@ -51,6 +52,7 @@ pub(crate) mod innerlude {
pub use crate::fragment::*;
pub use crate::generational_box::*;
pub use crate::global_context::*;
pub use crate::launch::*;
pub use crate::mutations::*;
pub use crate::nodes::*;
pub use crate::properties::*;
@ -75,10 +77,10 @@ pub(crate) mod innerlude {
pub use crate::innerlude::{
fc_to_builder, generation, schedule_update, schedule_update_any, use_hook, vdom_is_rendering,
AnyValue, Attribute, AttributeValue, CapturedError, Component, ComponentFunction, DynamicNode,
Element, ElementId, Event, Fragment, HasAttributes, IntoDynNode, MarkerWrapper, Mutation,
Mutations, NoOpMutations, Ok, Properties, Result, Runtime, ScopeId, ScopeState, SpawnIfAsync,
Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VNodeInner, VPlaceholder,
VText, VirtualDom, WriteMutations,
Element, ElementId, Event, Fragment, HasAttributes, IntoDynNode, LaunchConfig, MarkerWrapper,
Mutation, Mutations, NoOpMutations, Ok, Properties, Result, Runtime, ScopeId, ScopeState,
SpawnIfAsync, Task, Template, TemplateAttribute, TemplateNode, VComponent, VNode, VNodeInner,
VPlaceholder, VText, VirtualDom, WriteMutations,
};
/// The purpose of this module is to alleviate imports of many common types

View file

@ -17,7 +17,7 @@ pub fn check_app_exits(app: fn() -> Element) {
}
});
LaunchBuilder::desktop()
dioxus::LaunchBuilder::desktop()
.with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(false)))
.launch(app);

View file

@ -1,3 +1,4 @@
use dioxus_core::LaunchConfig;
use std::borrow::Cow;
use std::path::PathBuf;
use tao::window::{Icon, WindowBuilder};
@ -51,6 +52,8 @@ pub struct Config {
pub(crate) last_window_close_behavior: WindowCloseBehaviour,
}
impl LaunchConfig for Config {}
pub(crate) type WryProtocol = (
String,
Box<dyn Fn(HttpRequest<Vec<u8>>) -> HttpResponse<Cow<'static, [u8]>> + 'static>,

View file

@ -1,4 +1,4 @@
pub use crate::Config;
use crate::Config;
use crate::{
app::App,
ipc::{IpcMethod, UserWindowEvent},
@ -82,8 +82,8 @@ pub fn launch_virtual_dom(virtual_dom: VirtualDom, desktop_config: Config) -> !
/// Launches the WebView and runs the event loop, with configuration and root props.
pub fn launch(
root: fn() -> Element,
contexts: Vec<Box<dyn Fn() -> Box<dyn Any>>>,
platform_config: Config,
contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
platform_config: Vec<Box<dyn Any>>,
) -> ! {
let mut virtual_dom = VirtualDom::new(root);
@ -91,5 +91,10 @@ pub fn launch(
virtual_dom.insert_any_root_context(context());
}
let platform_config = *platform_config
.into_iter()
.find_map(|cfg| cfg.downcast::<Config>().ok())
.unwrap_or_default();
launch_virtual_dom(virtual_dom, platform_config)
}

View file

@ -35,11 +35,11 @@ fn main() {
}
fn app() -> Element {
rsx!{
rsx! {
div {
"hello world!"
}
})
}
}
```

View file

@ -44,7 +44,7 @@ To launch an app, we use the `launch` method and use features in `Cargo.toml` to
use dioxus::prelude::*;
fn main() {
launch(App);
dioxus::launch(App);
}
// The #[component] attribute streamlines component creation.
@ -239,7 +239,7 @@ Using components, templates, and hooks, we can build a simple app.
use dioxus::prelude::*;
fn main() {
launch(App);
dioxus::launch(App);
}
#[component]

View file

@ -42,7 +42,7 @@ To launch an app, we use the `launch` method and use features in `Cargo.toml` to
use dioxus::prelude::*;
fn main() {
launch(App);
dioxus::launch(App);
}
// The #[component] attribute streamlines component creation.
@ -184,7 +184,7 @@ Using components, rsx, and hooks, we can build a simple app.
use dioxus::prelude::*;
fn main() {
launch(App);
dioxus::launch(App);
}
#[component]

View file

@ -2,20 +2,22 @@
#![allow(clippy::new_without_default)]
#![allow(unused)]
use dioxus_config_macro::*;
use dioxus_core::LaunchConfig;
use std::any::Any;
use crate::prelude::*;
/// A builder for a fullstack app.
#[must_use]
pub struct LaunchBuilder<Cfg: 'static = (), ContextFn: ?Sized = ValidContext> {
launch_fn: LaunchFn<Cfg, ContextFn>,
contexts: Vec<Box<ContextFn>>,
platform_config: Option<Cfg>,
pub struct LaunchBuilder {
launch_fn: LaunchFn,
contexts: Vec<ContextFn>,
configs: Vec<Box<dyn Any>>,
}
pub type LaunchFn<Cfg, Context> = fn(fn() -> Element, Vec<Box<Context>>, Cfg);
pub type LaunchFn = fn(fn() -> Element, Vec<ContextFn>, Vec<Box<dyn Any>>);
/// A context function is a Send and Sync closure that returns a boxed trait object
pub type ContextFn = Box<dyn Fn() -> Box<dyn Any> + Send + Sync + 'static>;
#[cfg(any(
feature = "fullstack",
@ -54,69 +56,74 @@ impl LaunchBuilder {
note = "No renderer is enabled. You must enable a renderer feature on the dioxus crate before calling the launch function.\nAdd `web`, `desktop`, `mobile`, `fullstack`, or `static-generation` to the `features` of dioxus field in your Cargo.toml.\n# Example\n```toml\n# ...\n[dependencies]\ndioxus = { version = \"0.5.0\", features = [\"web\"] }\n# ...\n```"
)
)]
pub fn new() -> LaunchBuilder<current_platform::Config, ValidContext> {
pub fn new() -> LaunchBuilder {
LaunchBuilder {
// We can't use the `current_platform::launch` function directly because it may return ! or ()
launch_fn: |root, contexts, cfg| current_platform::launch(root, contexts, cfg),
contexts: Vec::new(),
platform_config: None,
configs: Vec::new(),
}
}
/// Launch your web application.
#[cfg(feature = "web")]
#[cfg_attr(docsrs, doc(cfg(feature = "web")))]
pub fn web() -> LaunchBuilder<dioxus_web::Config, UnsendContext> {
pub fn web() -> LaunchBuilder {
LaunchBuilder {
launch_fn: dioxus_web::launch::launch,
launch_fn: web_launch,
contexts: Vec::new(),
platform_config: None,
configs: Vec::new(),
}
}
/// Launch your desktop application.
#[cfg(feature = "desktop")]
#[cfg_attr(docsrs, doc(cfg(feature = "desktop")))]
pub fn desktop() -> LaunchBuilder<dioxus_desktop::Config, UnsendContext> {
pub fn desktop() -> LaunchBuilder {
LaunchBuilder {
launch_fn: |root, contexts, cfg| dioxus_desktop::launch::launch(root, contexts, cfg),
contexts: Vec::new(),
platform_config: None,
configs: Vec::new(),
}
}
/// Launch your fullstack application.
#[cfg(feature = "fullstack")]
#[cfg_attr(docsrs, doc(cfg(feature = "fullstack")))]
pub fn fullstack() -> LaunchBuilder<dioxus_fullstack::Config, SendContext> {
/// Launch your fullstack axum server.
#[cfg(all(feature = "fullstack", feature = "server"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "fullstack", feature = "server"))))]
pub fn server() -> LaunchBuilder {
LaunchBuilder {
launch_fn: |root, contexts, cfg| dioxus_fullstack::launch::launch(root, contexts, cfg),
launch_fn: |root, contexts, cfg| {
dioxus_fullstack::server::launch::launch(root, contexts, cfg)
},
contexts: Vec::new(),
platform_config: None,
configs: Vec::new(),
}
}
/// Launch your static site generation application.
#[cfg(feature = "static-generation")]
#[cfg_attr(docsrs, doc(cfg(feature = "static-generation")))]
pub fn static_generation() -> LaunchBuilder<dioxus_static_site_generation::Config, SendContext>
{
#[cfg(all(feature = "static-generation", feature = "server"))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "static-generation", feature = "server")))
)]
pub fn static_generation() -> LaunchBuilder {
LaunchBuilder {
launch_fn: |root, contexts, cfg| {
dioxus_static_site_generation::launch::launch(root, contexts, cfg)
},
contexts: Vec::new(),
platform_config: None,
configs: Vec::new(),
}
}
/// Launch your fullstack application.
#[cfg(feature = "mobile")]
#[cfg_attr(docsrs, doc(cfg(feature = "mobile")))]
pub fn mobile() -> LaunchBuilder<dioxus_mobile::Config, UnsendContext> {
pub fn mobile() -> LaunchBuilder {
LaunchBuilder {
launch_fn: |root, contexts, cfg| dioxus_mobile::launch::launch(root, contexts, cfg),
contexts: Vec::new(),
platform_config: None,
configs: Vec::new(),
}
}
@ -132,7 +139,7 @@ impl LaunchBuilder {
/// #[derive(Default)]
/// struct Config;
///
/// fn my_custom_launcher(root: fn() -> Element, contexts: Vec<Box<dyn Any>>, cfg: Config) {
/// fn my_custom_launcher(root: fn() -> Element, contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>, cfg: Vec<Box<dyn Any>>) {
/// println!("launching with root: {:?}", root());
/// loop {
/// println!("running...");
@ -145,42 +152,24 @@ impl LaunchBuilder {
/// }
/// }
///
/// LaunchBuilder::custom(my_custom_launcher).launch(app);
/// dioxus::LaunchBuilder::custom(my_custom_launcher).launch(app);
/// ```
pub fn custom<Config, Context: ?Sized>(
launch_fn: LaunchFn<Config, Context>,
) -> LaunchBuilder<Config, Context> {
pub fn custom(launch_fn: LaunchFn) -> LaunchBuilder {
LaunchBuilder {
launch_fn,
contexts: vec![],
platform_config: None,
configs: Vec::new(),
}
}
}
// Fullstack platform builder
impl<Cfg> LaunchBuilder<Cfg, UnsendContext> {
/// Inject state into the root component's context that is created on the thread that the app is launched on.
pub fn with_context_provider(mut self, state: impl Fn() -> Box<dyn Any> + 'static) -> Self {
self.contexts.push(Box::new(state) as Box<UnsendContext>);
self
}
/// Inject state into the root component's context.
pub fn with_context(mut self, state: impl Any + Clone + 'static) -> Self {
self.contexts
.push(Box::new(move || Box::new(state.clone())));
self
}
}
impl<Cfg> LaunchBuilder<Cfg, SendContext> {
impl LaunchBuilder {
/// Inject state into the root component's context that is created on the thread that the app is launched on.
pub fn with_context_provider(
mut self,
state: impl Fn() -> Box<dyn Any + Send + Sync> + Send + Sync + 'static,
state: impl Fn() -> Box<dyn Any> + Send + Sync + 'static,
) -> Self {
self.contexts.push(Box::new(state) as Box<SendContext>);
self.contexts.push(Box::new(state));
self
}
@ -192,38 +181,10 @@ impl<Cfg> LaunchBuilder<Cfg, SendContext> {
}
}
/// A trait for converting a type into a platform-specific config:
/// - A unit value will be converted into `None`
/// - Any config will be converted into `Some(config)`
/// - If the config is for another platform, it will be converted into `None`
pub trait TryIntoConfig<Config = Self> {
fn into_config(self, config: &mut Option<Config>);
}
// A config can always be converted into itself
impl<Cfg> TryIntoConfig<Cfg> for Cfg {
fn into_config(self, config: &mut Option<Cfg>) {
*config = Some(self);
}
}
// The unit type can be converted into the current platform config.
// This makes it possible to use the `desktop!`, `web!`, etc macros with the launch API.
#[cfg(any(
feature = "liveview",
feature = "desktop",
feature = "mobile",
feature = "web",
feature = "fullstack"
))]
impl TryIntoConfig<current_platform::Config> for () {
fn into_config(self, config: &mut Option<current_platform::Config>) {}
}
impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
impl LaunchBuilder {
/// Provide a platform-specific config to the builder.
pub fn with_cfg(mut self, config: impl TryIntoConfig<Cfg>) -> Self {
config.into_config(&mut self.platform_config);
pub fn with_cfg(mut self, config: impl LaunchConfig) -> Self {
self.configs.push(Box::new(config));
self
}
@ -231,7 +192,7 @@ impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
#[cfg(any(feature = "static-generation", feature = "web"))]
/// Launch your application.
pub fn launch(self, app: fn() -> Element) {
let cfg = self.platform_config.unwrap_or_default();
let cfg = self.configs;
(self.launch_fn)(app, self.contexts, cfg)
}
@ -239,7 +200,7 @@ impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
#[cfg(not(any(feature = "static-generation", feature = "web")))]
/// Launch your application.
pub fn launch(self, app: fn() -> Element) -> ! {
let cfg = self.platform_config.unwrap_or_default();
let cfg = self.configs;
(self.launch_fn)(app, self.contexts, cfg);
unreachable!("Launching an application will never exit")
@ -256,147 +217,67 @@ impl<Cfg: Default + 'static, ContextFn: ?Sized> LaunchBuilder<Cfg, ContextFn> {
/// - `web`
/// - `liveview`
mod current_platform {
macro_rules! if_else_cfg {
(if $attr:meta { $($then:item)* } else { $($else:item)* }) => {
$(
#[cfg($attr)]
$then
)*
$(
#[cfg(not($attr))]
$else
)*
};
}
use crate::prelude::TryIntoConfig;
#[cfg(all(feature = "fullstack", feature = "server"))]
pub use dioxus_fullstack::server::launch::*;
#[cfg(feature = "fullstack")]
pub use dioxus_fullstack::launch::*;
#[cfg(all(feature = "fullstack", feature = "axum"))]
impl TryIntoConfig<crate::launch::current_platform::Config>
for ::dioxus_fullstack::prelude::ServeConfigBuilder
{
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {
match config {
Some(config) => config.set_server_config(self),
None => {
*config = Some(
crate::launch::current_platform::Config::new().with_server_config(self),
)
}
}
}
}
#[cfg(any(feature = "desktop", feature = "mobile"))]
if_else_cfg! {
if not(feature = "fullstack") {
#[cfg(feature = "desktop")]
#[cfg(all(
feature = "desktop",
not(all(feature = "fullstack", feature = "server"))
))]
pub use dioxus_desktop::launch::*;
#[cfg(not(feature = "desktop"))]
#[cfg(all(
feature = "mobile",
not(feature = "desktop"),
not(all(feature = "fullstack", feature = "server"))
))]
pub use dioxus_mobile::launch::*;
} else {
if_else_cfg! {
if feature = "desktop" {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_desktop::Config {
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {
match config {
Some(config) => config.set_desktop_config(self),
None => *config = Some(crate::launch::current_platform::Config::new().with_desktop_config(self)),
}
}
}
} else {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_mobile::Config {
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {
match config {
Some(config) => config.set_mobile_cfg(self),
None => *config = Some(crate::launch::current_platform::Config::new().with_mobile_cfg(self)),
}
}
}
}
}
}
}
#[cfg(feature = "static-generation")]
if_else_cfg! {
if all(not(feature = "fullstack"), not(feature = "desktop"), not(feature = "mobile")) {
#[cfg(all(
all(feature = "static-generation", feature = "server"),
not(all(feature = "fullstack", feature = "server")),
not(feature = "desktop"),
not(feature = "mobile")
))]
pub use dioxus_static_site_generation::launch::*;
} else {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_static_site_generation::Config {
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {}
}
}
}
#[cfg(feature = "web")]
if_else_cfg! {
if not(any(feature = "desktop", feature = "mobile", feature = "fullstack", feature = "static-generation")) {
pub use dioxus_web::launch::*;
} else {
if_else_cfg! {
if feature = "fullstack" {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_web::Config {
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {
match config {
Some(config) => config.set_web_config(self),
None => *config = Some(crate::launch::current_platform::Config::new().with_web_config(self)),
}
}
}
} else {
impl TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_web::Config {
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {}
}
}
}
}
}
#[cfg(feature = "liveview")]
if_else_cfg! {
if
not(any(
#[cfg(all(
feature = "web",
feature = "desktop",
feature = "mobile",
feature = "fullstack",
feature = "static-generation"
))
{
not(all(feature = "fullstack", feature = "server")),
not(all(feature = "static-generation", feature = "server")),
not(feature = "desktop"),
not(feature = "mobile"),
))]
pub fn launch(
root: fn() -> dioxus_core::Element,
contexts: Vec<super::ContextFn>,
platform_config: Vec<Box<dyn std::any::Any>>,
) {
super::web_launch(root, contexts, platform_config);
}
#[cfg(all(
feature = "liveview",
not(all(feature = "fullstack", feature = "server")),
not(all(feature = "static-generation", feature = "server")),
not(feature = "desktop"),
not(feature = "mobile"),
not(feature = "web"),
))]
pub use dioxus_liveview::launch::*;
} else {
impl<R: ::dioxus_liveview::LiveviewRouter> TryIntoConfig<crate::launch::current_platform::Config> for ::dioxus_liveview::Config<R> {
fn into_config(self, config: &mut Option<crate::launch::current_platform::Config>) {}
}
}
}
#[cfg(not(any(
feature = "liveview",
all(feature = "fullstack", feature = "server"),
all(feature = "static-generation", feature = "server"),
feature = "desktop",
feature = "mobile",
feature = "web",
feature = "fullstack",
feature = "static-generation"
)))]
pub type Config = ();
#[cfg(not(any(
feature = "liveview",
feature = "desktop",
feature = "mobile",
feature = "web",
feature = "fullstack",
feature = "static-generation"
)))]
pub fn launch(
root: fn() -> dioxus_core::Element,
contexts: Vec<Box<super::ValidContext>>,
platform_config: (),
contexts: Vec<super::ContextFn>,
platform_config: Vec<Box<dyn std::any::Any>>,
) -> ! {
#[cfg(feature = "third-party-renderer")]
panic!("No first party renderer feature enabled. It looks like you are trying to use a third party renderer. You will need to use the launch function from the third party renderer crate.");
@ -409,22 +290,6 @@ mod current_platform {
macro_rules! impl_launch {
($($return_type:tt),*) => {
/// Launch your application without any additional configuration. See [`LaunchBuilder`] for more options.
// If you aren't using a third party renderer and this is not a docs.rs build, generate a warning about no renderer being enabled
#[cfg_attr(
all(not(any(
docsrs,
feature = "third-party-renderer",
feature = "liveview",
feature = "desktop",
feature = "mobile",
feature = "web",
feature = "fullstack",
feature = "static-generation"
))),
deprecated(
note = "No renderer is enabled. You must enable a renderer feature on the dioxus crate before calling the launch function.\nAdd `web`, `desktop`, `mobile`, `fullstack`, or `static-generation` to the `features` of dioxus field in your Cargo.toml.\n# Example\n```toml\n# ...\n[dependencies]\ndioxus = { version = \"0.5.0\", features = [\"web\"] }\n# ...\n```"
)
)]
pub fn launch(app: fn() -> Element) -> $($return_type)* {
#[allow(deprecated)]
LaunchBuilder::new().launch(app)
@ -439,29 +304,40 @@ impl_launch!(());
impl_launch!(!);
#[cfg(feature = "web")]
#[cfg_attr(docsrs, doc(cfg(feature = "web")))]
/// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options.
pub fn launch_web(app: fn() -> Element) {
LaunchBuilder::web().launch(app)
}
fn web_launch(
root: fn() -> dioxus_core::Element,
contexts: Vec<super::ContextFn>,
platform_config: Vec<Box<dyn std::any::Any>>,
) {
// If the server feature is enabled, launch the client with hydration enabled
#[cfg(any(feature = "static-generation", feature = "fullstack"))]
{
let platform_config = platform_config
.into_iter()
.find_map(|cfg| cfg.downcast::<dioxus_web::Config>().ok())
.unwrap_or_default()
.hydrate(true);
#[cfg(feature = "desktop")]
#[cfg_attr(docsrs, doc(cfg(feature = "desktop")))]
/// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options.
pub fn launch_desktop(app: fn() -> Element) {
LaunchBuilder::desktop().launch(app)
}
let factory = move || {
let mut vdom = dioxus_core::VirtualDom::new(root);
for context in contexts {
vdom.insert_any_root_context(context());
}
#[cfg(feature = "document")]
{
#[cfg(feature = "fullstack")]
use dioxus_fullstack::document;
#[cfg(all(feature = "static-generation", not(feature = "fullstack")))]
use dioxus_static_site_generation::document;
let document = std::rc::Rc::new(document::web::FullstackWebDocument)
as std::rc::Rc<dyn crate::prelude::Document>;
vdom.provide_root_context(document);
}
vdom
};
#[cfg(feature = "fullstack")]
#[cfg_attr(docsrs, doc(cfg(feature = "fullstack")))]
/// Launch your fullstack application without any additional configuration. See [`LaunchBuilder`] for more options.
pub fn launch_fullstack(app: fn() -> Element) {
LaunchBuilder::fullstack().launch(app)
}
#[cfg(feature = "mobile")]
#[cfg_attr(docsrs, doc(cfg(feature = "mobile")))]
/// Launch your mobile application without any additional configuration. See [`LaunchBuilder`] for more options.
pub fn launch_mobile(app: fn() -> Element) {
LaunchBuilder::mobile().launch(app)
dioxus_web::launch::launch_virtual_dom(factory(), platform_config)
}
#[cfg(not(any(feature = "static-generation", feature = "fullstack")))]
dioxus_web::launch::launch(root, contexts, platform_config);
}

View file

@ -34,8 +34,7 @@ mod launch;
#[cfg(feature = "launch")]
#[cfg_attr(docsrs, doc(cfg(feature = "launch")))]
#[allow(deprecated)]
pub use launch::launch;
pub use crate::launch::*;
#[cfg(feature = "hooks")]
#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]
@ -60,9 +59,6 @@ pub use dioxus_html as html;
pub use dioxus_core_macro as core_macro;
pub mod prelude {
#[cfg(feature = "launch")]
#[cfg_attr(docsrs, doc(cfg(feature = "launch")))]
pub use crate::launch::*;
#[cfg(feature = "hooks")]
#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))]

View file

@ -37,7 +37,77 @@ Full stack Dioxus in under 30 lines of code
use dioxus::prelude::*;
fn main() {
launch(App);
dioxus::launch(App);
}
#[component]
fn App() -> Element {
let mut meaning = use_signal(|| None);
rsx! {
h1 { "Meaning of life: {meaning:?}" }
button {
onclick: move |_| async move {
if let Ok(data) = get_meaning("life the universe and everything".into()).await {
meaning.set(data);
}
},
"Run a server function"
}
}
}
#[server]
async fn get_meaning(of: String) -> Result<Option<u32>, ServerFnError> {
Ok(of.contains("life").then(|| 42))
}
```
## Axum Integration
If you have an existing Axum router or you need more control over the server, you can use the [`DioxusRouterExt`](https://docs.rs/dioxus-fullstack/0.6.0-alpha.2/dioxus_fullstack/prelude/trait.DioxusRouterExt.html) trait to integrate with your existing Axum router.
First, make sure your `axum` dependency is optional and enabled by the server feature flag. Axum cannot be compiled to wasm, so if it is enabled by default, it will cause a compile error:
```toml
[dependencies]
dioxus = { version = "*", features = ["fullstack"] }
axum = { version = "0.7.0", optional = true }
[features]
server = ["dep:axum", "dioxus/server"]
web = ["dioxus/web"]
```
Then we can set up dioxus with the axum server:
```rust, no_run
#![allow(non_snake_case)]
use dioxus::prelude::*;
// The entry point for the server
#[cfg(feature = "server")]
fn main() {
// Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address
// and we use the generated address the CLI gives us
let address = dioxus_cli_config::RuntimeCLIArguments::fullstack_address_or_localhost();
// Set up the axum router
let router = axum::Router::new()
// You can add a dioxus application to the router with the `serve_dioxus_application` method
// This will add a fallback route to the router that will serve your component and server functions
.serve_dioxus_application(ServeConfigBuilder::default(), App);
// Finally, we can launch the server
let router = router.into_make_service();
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
axum::serve(listener, router).await.unwrap();
}
// For any other platform, we just launch the app
#[cfg(not(feature = "server"))]
fn main() {
dioxus::launch(App);
}
#[component]
@ -111,7 +181,7 @@ fn main() {
// For any other platform, we just launch the app
#[cfg(not(feature = "server"))]
fn main() {
launch(App);
dioxus::launch(App);
}
#[component]

View file

@ -1,289 +0,0 @@
//! Launch helper macros for fullstack apps
#![allow(unused)]
use crate::prelude::*;
use dioxus_lib::prelude::*;
use std::sync::Arc;
/// Settings for a fullstack app.
///
/// Depending on what features are enabled, you can pass in configurations for each client platform as well as the server:
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the server config if the server feature is enabled
/// server_only! {
/// cfg = cfg.with_server_config(ServeConfigBuilder::default());
/// }
///
/// // Only set the web config if the web feature is enabled
/// web! {
/// cfg = cfg.with_web_config(dioxus::web::Config::default());
/// }
///
/// // Only set the desktop config if the desktop feature is enabled
/// desktop! {
/// cfg = cfg.with_desktop_config(dioxus::desktop::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
pub struct Config {
#[cfg(feature = "server")]
pub(crate) server_cfg: ServeConfigBuilder,
#[cfg(feature = "web")]
pub(crate) web_cfg: dioxus_web::Config,
#[cfg(feature = "desktop")]
pub(crate) desktop_cfg: dioxus_desktop::Config,
#[cfg(feature = "mobile")]
pub(crate) mobile_cfg: dioxus_mobile::Config,
}
#[allow(clippy::derivable_impls)]
impl Default for Config {
fn default() -> Self {
Self {
#[cfg(feature = "server")]
server_cfg: ServeConfigBuilder::new(),
#[cfg(feature = "web")]
web_cfg: dioxus_web::Config::default(),
#[cfg(feature = "desktop")]
desktop_cfg: dioxus_desktop::Config::default(),
#[cfg(feature = "mobile")]
mobile_cfg: dioxus_mobile::Config::default(),
}
}
}
impl Config {
/// Create a new config for a fullstack app.
pub fn new() -> Self {
Self::default()
}
/// Set the incremental renderer config. The incremental config can be used to improve
/// performance of heavy routes by caching the rendered html in memory and/or the file system.
///
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the server config if the server feature is enabled
/// server_only! {
/// cfg = cfg.incremental(IncrementalRendererConfig::default().with_memory_cache_limit(10000));
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "server")]
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
pub fn incremental(self, cfg: IncrementalRendererConfig) -> Self {
Self {
server_cfg: self.server_cfg.incremental(cfg),
..self
}
}
/// Set the server config
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the server config if the server feature is enabled
/// server_only! {
/// cfg = cfg.with_server_config(ServeConfigBuilder::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "server")]
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
pub fn with_server_config(self, server_cfg: ServeConfigBuilder) -> Self {
Self { server_cfg, ..self }
}
/// Set the server config by modifying the config in place
///
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the server config if the server feature is enabled
/// server_only! {
/// cfg.set_server_config(ServeConfigBuilder::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "server")]
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]
pub fn set_server_config(&mut self, server_cfg: ServeConfigBuilder) {
self.server_cfg = server_cfg;
}
/// Set the web config
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the web config if the server feature is enabled
/// web! {
/// cfg = cfg.with_web_config(dioxus::web::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "web")]
#[cfg_attr(docsrs, doc(cfg(feature = "web")))]
pub fn with_web_config(self, web_cfg: dioxus_web::Config) -> Self {
Self { web_cfg, ..self }
}
/// Set the server config by modifying the config in place
///
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the web config if the server feature is enabled
/// web! {
/// cfg.set_web_config(dioxus::web::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "web")]
#[cfg_attr(docsrs, doc(cfg(feature = "web")))]
pub fn set_web_config(&mut self, web_cfg: dioxus_web::Config) {
self.web_cfg = web_cfg;
}
/// Set the desktop config
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the desktop config if the server feature is enabled
/// desktop! {
/// cfg = cfg.with_desktop_config(dioxus::desktop::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "desktop")]
#[cfg_attr(docsrs, doc(cfg(feature = "desktop")))]
pub fn with_desktop_config(self, desktop_cfg: dioxus_desktop::Config) -> Self {
Self {
desktop_cfg,
..self
}
}
/// Set the desktop config by modifying the config in place
///
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the desktop config if the server feature is enabled
/// desktop! {
/// cfg.set_desktop_config(dioxus::desktop::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// ```
#[cfg(feature = "desktop")]
#[cfg_attr(docsrs, doc(cfg(feature = "desktop")))]
pub fn set_desktop_config(&mut self, desktop_cfg: dioxus_desktop::Config) {
self.desktop_cfg = desktop_cfg;
}
/// Set the mobile config
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the mobile config if the server feature is enabled
/// mobile! {
/// cfg = cfg.with_mobile_cfg(dioxus::mobile::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// Set the mobile config.
#[cfg(feature = "mobile")]
#[cfg_attr(docsrs, doc(cfg(feature = "mobile")))]
pub fn with_mobile_cfg(self, mobile_cfg: dioxus_mobile::Config) -> Self {
Self { mobile_cfg, ..self }
}
/// Set the mobile config by modifying the config in place
/// ```rust, no_run
/// # fn app() -> Element { todo!() }
/// use dioxus::prelude::*;
///
/// let mut cfg = dioxus::fullstack::Config::new();
///
/// // Only set the mobile config if the server feature is enabled
/// mobile! {
/// cfg.set_mobile_cfg(dioxus::mobile::Config::default());
/// }
///
/// // Finally, launch the app with the config
/// LaunchBuilder::new()
/// .with_cfg(cfg)
/// .launch(app);
/// Set the mobile config.
#[cfg(feature = "mobile")]
#[cfg_attr(docsrs, doc(cfg(feature = "mobile")))]
pub fn set_mobile_cfg(&mut self, mobile_cfg: dioxus_mobile::Config) {
self.mobile_cfg = mobile_cfg;
}
}

View file

@ -1,8 +1,8 @@
//! This module contains the document providers for the fullstack platform.
#[cfg(feature = "server")]
pub(crate) mod server;
pub mod server;
#[cfg(feature = "server")]
pub use server::ServerDocument;
#[cfg(all(feature = "web", feature = "document"))]
pub(crate) mod web;
pub mod web;

View file

@ -11,7 +11,8 @@ fn head_element_written_on_server() -> bool {
.unwrap_or_default()
}
pub(crate) struct FullstackWebDocument;
/// A document provider for fullstack web clients
pub struct FullstackWebDocument;
impl Document for FullstackWebDocument {
fn new_evaluator(

View file

@ -1,171 +0,0 @@
//! This module contains the `launch` function, which is the main entry point for dioxus fullstack
use std::{any::Any, sync::Arc};
use dioxus_lib::prelude::{Element, VirtualDom};
pub use crate::Config;
#[allow(unused)]
pub(crate) type ContextProviders = Arc<
Vec<Box<dyn Fn() -> Box<dyn std::any::Any + Send + Sync + 'static> + Send + Sync + 'static>>,
>;
#[allow(unused)]
fn virtual_dom_factory(
root: fn() -> Element,
contexts: ContextProviders,
) -> impl Fn() -> VirtualDom + 'static {
move || {
let mut vdom = VirtualDom::new(root);
for context in &*contexts {
vdom.insert_any_root_context(context());
}
vdom
}
}
#[cfg(feature = "server")]
/// Launch a fullstack app with the given root component, contexts, and config.
#[allow(unused)]
pub fn launch(
root: fn() -> Element,
contexts: Vec<Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>>,
platform_config: Config,
) -> ! {
let contexts = Arc::new(contexts);
let factory = virtual_dom_factory(root, contexts.clone());
#[cfg(all(feature = "server", not(target_arch = "wasm32")))]
tokio::runtime::Runtime::new()
.unwrap()
.block_on(async move {
launch_server(platform_config, factory, contexts).await;
});
unreachable!("Launching a fullstack app should never return")
}
#[cfg(all(not(feature = "server"), feature = "web"))]
/// Launch a fullstack app with the given root component, contexts, and config.
#[allow(unused)]
pub fn launch(
root: fn() -> Element,
#[allow(unused_mut)] mut contexts: Vec<
Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>,
>,
platform_config: Config,
) {
let contexts = Arc::new(contexts);
let mut factory = virtual_dom_factory(root, contexts);
let cfg = platform_config.web_cfg.hydrate(true);
#[cfg(feature = "document")]
let factory = move || {
let mut vdom = factory();
let document = std::rc::Rc::new(crate::document::web::FullstackWebDocument)
as std::rc::Rc<dyn dioxus_lib::prelude::document::Document>;
vdom.provide_root_context(document);
vdom
};
dioxus_web::launch::launch_virtual_dom(factory(), cfg)
}
#[cfg(all(not(any(feature = "server", feature = "web")), feature = "desktop"))]
/// Launch a fullstack app with the given root component, contexts, and config.
#[allow(unused)]
pub fn launch(
root: fn() -> Element,
contexts: Vec<Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>>,
platform_config: Config,
) -> ! {
let contexts = Arc::new(contexts);
let factory = virtual_dom_factory(root, contexts);
let cfg = platform_config.desktop_cfg;
dioxus_desktop::launch::launch_virtual_dom(factory(), cfg)
}
#[cfg(all(
not(any(feature = "server", feature = "web", feature = "desktop")),
feature = "mobile"
))]
/// Launch a fullstack app with the given root component, contexts, and config.
#[allow(unused)]
pub fn launch(
root: fn() -> Element,
contexts: Vec<Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>>,
platform_config: Config,
) -> ! {
let contexts = Arc::new(contexts);
let factory = virtual_dom_factory(root, contexts.clone());
let cfg = platform_config.mobile_cfg;
dioxus_mobile::launch::launch_virtual_dom(factory(), cfg)
}
#[cfg(not(any(
feature = "server",
feature = "web",
feature = "desktop",
feature = "mobile"
)))]
/// Launch a fullstack app with the given root component, contexts, and config.
#[allow(unused)]
pub fn launch(
root: fn() -> Element,
contexts: Vec<Box<dyn Fn() -> Box<dyn Any + Send + Sync> + Send + Sync>>,
platform_config: Config,
) -> ! {
panic!("No platform feature enabled. Please enable one of the following features: axum, desktop, or web to use the launch API.")
}
#[cfg(feature = "server")]
#[allow(unused)]
/// Launch a server application
async fn launch_server(
platform_config: Config,
build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static,
context_providers: ContextProviders,
) {
// Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address
// and we use the generated address the CLI gives us
let address = dioxus_cli_config::fullstack_address_or_localhost();
#[cfg(feature = "axum")]
{
use crate::axum_adapter::DioxusRouterExt;
#[allow(unused_mut)]
let mut router =
axum::Router::new().register_server_functions_with_context(context_providers);
#[cfg(not(any(feature = "desktop", feature = "mobile")))]
{
use crate::prelude::RenderHandleState;
use crate::prelude::SSRState;
match platform_config.server_cfg.build() {
Ok(cfg) => {
router = router.serve_static_assets();
router = router.fallback(
axum::routing::get(crate::axum_adapter::render_handler).with_state(
RenderHandleState::new_with_virtual_dom_factory(cfg, build_virtual_dom),
),
);
}
Err(err) => {
tracing::trace!("Failed to create render handler. This is expected if you are only using fullstack for desktop/mobile server functions: {}", err);
}
}
}
let router = router.into_make_service();
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
axum::serve(listener, router).await.unwrap();
}
#[cfg(not(feature = "axum"))]
{
panic!("Launching with dioxus fullstack requires the axum feature. If you are using a community fullstack adapter, please check the documentation for that adapter to see how to launch the application.");
}
}

View file

@ -10,13 +10,9 @@ mod html_storage;
#[cfg(feature = "axum")]
#[cfg_attr(docsrs, doc(cfg(feature = "axum")))]
mod axum_adapter;
pub mod server;
mod config;
mod hooks;
pub mod launch;
pub use config::*;
pub mod document;
#[cfg(feature = "server")]
@ -39,7 +35,7 @@ pub mod prelude {
#[cfg(feature = "axum")]
#[cfg_attr(docsrs, doc(cfg(feature = "axum")))]
pub use crate::axum_adapter::*;
pub use crate::server::*;
#[cfg(feature = "server")]
#[cfg_attr(docsrs, doc(cfg(feature = "server")))]

View file

@ -5,6 +5,8 @@ use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use dioxus_lib::prelude::dioxus_core::LaunchConfig;
/// 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, Default)]
pub struct ServeConfigBuilder {
@ -14,6 +16,8 @@ pub struct ServeConfigBuilder {
pub(crate) incremental: Option<dioxus_isrg::IncrementalRendererConfig>,
}
impl LaunchConfig for ServeConfigBuilder {}
impl ServeConfigBuilder {
/// Create a new ServeConfigBuilder with incremental static generation disabled and the default index.html settings
pub fn new() -> Self {
@ -239,6 +243,8 @@ pub struct ServeConfig {
pub(crate) incremental: Option<dioxus_isrg::IncrementalRendererConfig>,
}
impl LaunchConfig for ServeConfig {}
impl ServeConfig {
/// Create a new ServeConfig
pub fn new() -> Result<Self, UnableToLoadIndex> {

Some files were not shown because too many files have changed in this diff Show more