From 2ef406982e57f006120eb0a91f2a98908679fbd1 Mon Sep 17 00:00:00 2001 From: Miles Murgaw Date: Wed, 3 Jul 2024 00:36:44 -0400 Subject: [PATCH] Use Manganis Linker System (#2561) * feat: new manganis linker * revision: fmt, clippy, cleanup * revision: link subcommand * fix: async runtime * revision: remove working dir arg * revision: switch dep source * fix: matrix, playwright * fix: fullstack manganis --- .github/workflows/main.yml | 8 +- Cargo.lock | 73 +++++++++++-- Cargo.toml | 2 +- packages/cli/src/assets.rs | 17 +-- packages/cli/src/builder.rs | 132 +++++++++++++++-------- packages/cli/src/cli/check.rs | 32 +++--- packages/cli/src/cli/link.rs | 39 +++++++ packages/cli/src/cli/mod.rs | 6 ++ packages/cli/src/cli/plugin.rs | 2 +- packages/cli/src/cli/serve.rs | 8 +- packages/cli/src/lib.rs | 2 +- packages/cli/src/main.rs | 18 ++-- packages/cli/src/server/desktop/mod.rs | 86 +++++++-------- packages/cli/src/server/fullstack/mod.rs | 4 +- packages/cli/src/server/web/mod.rs | 71 ++++++------ 15 files changed, 330 insertions(+), 170 deletions(-) create mode 100644 packages/cli/src/cli/link.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b63f4da70..ac90c5fbb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -222,7 +222,7 @@ jobs: - { target: x86_64-pc-windows-msvc, os: windows-latest, - toolchain: "1.75.0", + toolchain: "1.76.0", cross: false, command: "test", args: "--all --tests", @@ -230,7 +230,7 @@ jobs: - { target: x86_64-apple-darwin, os: macos-latest, - toolchain: "1.75.0", + toolchain: "1.76.0", cross: false, command: "test", args: "--all --tests", @@ -238,7 +238,7 @@ jobs: - { target: aarch64-apple-ios, os: macos-latest, - toolchain: "1.75.0", + toolchain: "1.76.0", cross: false, command: "build", args: "--package dioxus-mobile", @@ -246,7 +246,7 @@ jobs: - { target: aarch64-linux-android, os: ubuntu-latest, - toolchain: "1.75.0", + toolchain: "1.76.0", cross: true, command: "build", args: "--package dioxus-mobile", diff --git a/Cargo.lock b/Cargo.lock index 4ccc9156b..cf163c6c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -906,7 +906,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.32.2", "rustc-demangle", ] @@ -1936,7 +1936,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa 1.0.11", - "phf 0.11.2", + "phf 0.8.0", "smallvec", ] @@ -5918,8 +5918,7 @@ dependencies = [ [[package]] name = "manganis-cli-support" version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d502b0db0ef8c880fecff174903815efedfacbcd5ea9a8bef96752f1e0d7eb6" +source = "git+https://github.com/DogeDark/dioxus-collect-assets/#6b6077150c854af6497d8b96d3a070635ab9b6c4" dependencies = [ "anyhow", "cargo-lock", @@ -5928,8 +5927,9 @@ dependencies = [ "image 0.25.1", "imagequant", "lightningcss", - "manganis-common", + "manganis-common 0.2.4 (git+https://github.com/DogeDark/dioxus-collect-assets/)", "mozjpeg", + "object 0.36.0", "petgraph", "png", "railwind", @@ -5938,6 +5938,7 @@ dependencies = [ "reqwest 0.11.27", "rustc-hash", "serde", + "serde_json", "toml 0.7.8", "tracing", "url", @@ -5960,13 +5961,29 @@ dependencies = [ "url", ] +[[package]] +name = "manganis-common" +version = "0.2.4" +source = "git+https://github.com/DogeDark/dioxus-collect-assets/#6b6077150c854af6497d8b96d3a070635ab9b6c4" +dependencies = [ + "anyhow", + "base64 0.21.7", + "home", + "infer 0.11.0", + "reqwest", + "serde", + "toml 0.7.8", + "tracing", + "url", +] + [[package]] name = "manganis-macro" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "704a0123ac90fa630b21a04fde56c29dfd5a7665c5e8f3639567989daa2d29d1" dependencies = [ - "manganis-common", + "manganis-common 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2", "quote", "syn 2.0.60", @@ -6554,6 +6571,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "flate2", + "memchr", + "ruzstd", + "wasmparser 0.208.1", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -8117,6 +8146,17 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +[[package]] +name = "ruzstd" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" +dependencies = [ + "byteorder", + "derive_more", + "twox-hash", +] + [[package]] name = "ryu" version = "1.0.17" @@ -9899,6 +9939,16 @@ dependencies = [ "utf-8", ] +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "typenum" version = "1.17.0" @@ -10132,7 +10182,7 @@ dependencies = [ "log", "walrus-macro", "wasm-encoder", - "wasmparser", + "wasmparser 0.80.2", ] [[package]] @@ -10419,6 +10469,15 @@ version = "0.80.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b" +[[package]] +name = "wasmparser" +version = "0.208.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd921789c9dcc495f589cb37d200155dee65b4a4beeb853323b5e24e0a5f9c58" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "web-sys" version = "0.3.69" diff --git a/Cargo.toml b/Cargo.toml index 00bdb60da..4d214137f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,7 @@ wasm-bindgen-futures = "0.4.42" html_parser = "0.7.0" thiserror = "1.0.40" prettyplease = { version = "0.2.16", features = ["verbatim"] } -manganis-cli-support = { version = "0.2.1", features = ["html"] } +manganis-cli-support = { git = "https://github.com/DogeDark/dioxus-collect-assets/", features = ["html"] } manganis = { version = "0.2.1" } interprocess = { version = "1.2.2", package = "interprocess-docfix" } diff --git a/packages/cli/src/assets.rs b/packages/cli/src/assets.rs index 6ed61cb15..8bb6d0b21 100644 --- a/packages/cli/src/assets.rs +++ b/packages/cli/src/assets.rs @@ -1,4 +1,5 @@ use brotli::enc::BrotliEncoderParams; +use std::fs; use std::path::Path; use std::{ffi::OsString, path::PathBuf}; use walkdir::WalkDir; @@ -10,12 +11,16 @@ use dioxus_cli_config::CrateConfig; use dioxus_cli_config::Platform; use manganis_cli_support::{AssetManifest, AssetManifestExt}; -pub fn asset_manifest(bin: Option<&str>, crate_config: &CrateConfig) -> AssetManifest { - AssetManifest::load_from_path( - bin, - crate_config.crate_dir.join("Cargo.toml"), - crate_config.workspace_dir.join("Cargo.lock"), - ) +/// The temp file name for passing manganis json from linker to current exec. +pub const MG_JSON_OUT: &str = "mg-out"; + +pub fn asset_manifest(config: &CrateConfig) -> AssetManifest { + let file_path = config.out_dir().join(MG_JSON_OUT); + let read = fs::read_to_string(&file_path).unwrap(); + _ = fs::remove_file(file_path); + let json: Vec = serde_json::from_str(&read).unwrap(); + + AssetManifest::load(json) } /// Create a head file that contains all of the imports for assets that the user project uses diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index abf05a53b..39a36a03a 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -4,6 +4,7 @@ use crate::{ AssetConfigDropGuard, }, error::{Error, Result}, + link::LinkCommand, tools::Tool, }; use anyhow::Context; @@ -83,13 +84,12 @@ pub fn build_web( let CrateConfig { crate_dir, target_dir, - executable, dioxus_config, .. } = config; let out_dir = config.out_dir(); - let _guard = AssetConfigDropGuard::new(); + let _asset_guard = AssetConfigDropGuard::new(); let _manganis_support = ManganisSupportGuard::default(); // start to build the assets @@ -114,54 +114,76 @@ pub fn build_web( } } - let cmd = subprocess::Exec::cmd("cargo") + let mut cargo_args = vec!["--target".to_string(), "wasm32-unknown-unknown".to_string()]; + + let mut cmd = subprocess::Exec::cmd("cargo") .set_rust_flags(rust_flags) .env("CARGO_TARGET_DIR", target_dir) .cwd(crate_dir) .arg("build") - .arg("--target") - .arg("wasm32-unknown-unknown") .arg("--message-format=json-render-diagnostics"); // TODO: make the initial variable mutable to simplify all the expressions // below. Look inside the `build_desktop()` as an example. - let cmd = if config.release { - cmd.arg("--release") + if config.release { + cargo_args.push("--release".to_string()); + } + if config.verbose { + cargo_args.push("--verbose".to_string()); } else { - cmd - }; - let cmd = if config.verbose { - cmd.arg("--verbose") - } else { - cmd.arg("--quiet") - }; + cargo_args.push("--quiet".to_string()); + } - let cmd = if config.custom_profile.is_some() { + if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap(); - cmd.arg("--profile").arg(custom_profile) - } else { - cmd - }; + cargo_args.push("--profile".to_string()); + cargo_args.push(custom_profile.to_string()); + } - let cmd = if config.features.is_some() { + if config.features.is_some() { let features_str = config.features.as_ref().unwrap().join(" "); - cmd.arg("--features").arg(features_str) - } else { - cmd - }; + cargo_args.push("--features".to_string()); + cargo_args.push(features_str); + } - let cmd = cmd.args(&config.cargo_args); + if let Some(target) = &config.target { + cargo_args.push("--target".to_string()); + cargo_args.push(target.clone()); + } - let cmd = match executable { - ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), - ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), - ExecutableType::Example(name) => cmd.arg("--example").arg(name), + cargo_args.append(&mut config.cargo_args.clone()); + + match &config.executable { + ExecutableType::Binary(name) => { + cargo_args.push("--bin".to_string()); + cargo_args.push(name.to_string()); + } + ExecutableType::Lib(name) => { + cargo_args.push("--lib".to_string()); + cargo_args.push(name.to_string()); + } + ExecutableType::Example(name) => { + cargo_args.push("--example".to_string()); + cargo_args.push(name.to_string()); + } }; + cmd = cmd.args(&cargo_args); let CargoBuildResult { warnings, output_location, } = prettier_build(cmd)?; + + // Start Manganis linker intercept. + let linker_args = vec![format!("{}", config.out_dir().display())]; + + manganis_cli_support::start_linker_intercept( + &LinkCommand::command_name(), + cargo_args, + Some(linker_args), + ) + .unwrap(); + let output_location = output_location.context("No output location found")?; // [2] Establish the output directory structure @@ -277,7 +299,7 @@ pub fn build_web( let assets = if !skip_assets { tracing::info!("Processing assets"); - let assets = asset_manifest(executable.executable(), config); + let assets = asset_manifest(config); process_assets(config, &assets)?; Some(assets) } else { @@ -337,7 +359,9 @@ pub fn build_desktop( build_assets(config)?; let _guard = dioxus_cli_config::__private::save_config(config); let _manganis_support = ManganisSupportGuard::default(); - let _guard = AssetConfigDropGuard::new(); + let _asset_guard = AssetConfigDropGuard::new(); + + let mut cargo_args = Vec::new(); let mut cmd = subprocess::Exec::cmd("cargo") .set_rust_flags(rust_flags) @@ -347,38 +371,60 @@ pub fn build_desktop( .arg("--message-format=json-render-diagnostics"); if config.release { - cmd = cmd.arg("--release"); + cargo_args.push("--release".to_string()); } if config.verbose { - cmd = cmd.arg("--verbose"); + cargo_args.push("--verbose".to_string()); } else { - cmd = cmd.arg("--quiet"); + cargo_args.push("--quiet".to_string()); } if config.custom_profile.is_some() { let custom_profile = config.custom_profile.as_ref().unwrap(); - cmd = cmd.arg("--profile").arg(custom_profile); + cargo_args.push("--profile".to_string()); + cargo_args.push(custom_profile.to_string()); } if config.features.is_some() { let features_str = config.features.as_ref().unwrap().join(" "); - cmd = cmd.arg("--features").arg(features_str); + cargo_args.push("--features".to_string()); + cargo_args.push(features_str); } if let Some(target) = &config.target { - cmd = cmd.arg("--target").arg(target); + cargo_args.push("--target".to_string()); + cargo_args.push(target.clone()); } - cmd = cmd.args(&config.cargo_args); + cargo_args.append(&mut config.cargo_args.clone()); - let cmd = match &config.executable { - ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), - ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), - ExecutableType::Example(name) => cmd.arg("--example").arg(name), + match &config.executable { + ExecutableType::Binary(name) => { + cargo_args.push("--bin".to_string()); + cargo_args.push(name.to_string()); + } + ExecutableType::Lib(name) => { + cargo_args.push("--lib".to_string()); + cargo_args.push(name.to_string()); + } + ExecutableType::Example(name) => { + cargo_args.push("--example".to_string()); + cargo_args.push(name.to_string()); + } }; + cmd = cmd.args(&cargo_args); let warning_messages = prettier_build(cmd)?; + // Start Manganis linker intercept. + let linker_args = vec![format!("{}", config.out_dir().display())]; + + manganis_cli_support::start_linker_intercept( + &LinkCommand::command_name(), + cargo_args, + Some(linker_args), + )?; + let file_name: String = config.executable.executable().unwrap().to_string(); let target_file = if cfg!(windows) { @@ -399,7 +445,7 @@ pub fn build_desktop( let assets = if !skip_assets { tracing::info!("Processing assets"); - let assets = asset_manifest(config.executable.executable(), config); + let assets = asset_manifest(config); // Collect assets process_assets(config, &assets)?; // Create the __assets_head.html file for bundling diff --git a/packages/cli/src/cli/check.rs b/packages/cli/src/cli/check.rs index 614a0c4de..f16a2c81a 100644 --- a/packages/cli/src/cli/check.rs +++ b/packages/cli/src/cli/check.rs @@ -16,22 +16,26 @@ pub struct Check { impl Check { // Todo: check the entire crate - pub async fn check(self) -> Result<()> { - match self.file { - // Default to checking the project - None => { - if let Err(e) = check_project_and_report().await { - eprintln!("error checking project: {}", e); - exit(1); + pub fn check(self) -> Result<()> { + let rt = tokio::runtime::Runtime::new().unwrap(); + + rt.block_on(async move { + match self.file { + // Default to checking the project + None => { + if let Err(e) = check_project_and_report().await { + eprintln!("error checking project: {}", e); + exit(1); + } + } + Some(file) => { + if let Err(e) = check_file_and_report(file).await { + eprintln!("failed to check file: {}", e); + exit(1); + } } } - Some(file) => { - if let Err(e) = check_file_and_report(file).await { - eprintln!("failed to check file: {}", e); - exit(1); - } - } - } + }); Ok(()) } diff --git a/packages/cli/src/cli/link.rs b/packages/cli/src/cli/link.rs new file mode 100644 index 000000000..c2c6fb2c0 --- /dev/null +++ b/packages/cli/src/cli/link.rs @@ -0,0 +1,39 @@ +use crate::{assets, error::Result}; +use clap::Parser; +use std::{fs, path::PathBuf}; + +#[derive(Clone, Debug, Parser)] +#[clap(name = "link", hide = true)] +pub struct LinkCommand { + // Allow us to accept any argument after `dx link` + #[clap(trailing_var_arg = true, allow_hyphen_values = true)] + pub args: Vec, +} + +impl LinkCommand { + pub fn link(self) -> Result<()> { + let Some((link_args, object_files)) = manganis_cli_support::linker_intercept(self.args) + else { + tracing::warn!("Invalid linker arguments."); + return Ok(()); + }; + + // Parse object files, deserialize JSON, & create a file to propogate JSON. + let json = manganis_cli_support::get_json_from_object_files(object_files); + let parsed = serde_json::to_string(&json).unwrap(); + + let out_dir = PathBuf::from(link_args.first().unwrap()); + fs::create_dir_all(&out_dir).unwrap(); + + let path = out_dir.join(assets::MG_JSON_OUT); + fs::write(path, parsed).unwrap(); + + Ok(()) + } + + /// We need to pass the subcommand name to Manganis so this + /// helps centralize where we set the subcommand "name". + pub fn command_name() -> String { + "link".to_string() + } +} diff --git a/packages/cli/src/cli/mod.rs b/packages/cli/src/cli/mod.rs index 0bbb0fba0..24d2f3c63 100644 --- a/packages/cli/src/cli/mod.rs +++ b/packages/cli/src/cli/mod.rs @@ -7,6 +7,7 @@ pub mod clean; pub mod config; pub mod create; pub mod init; +pub mod link; pub mod plugin; pub mod serve; pub mod translate; @@ -85,6 +86,10 @@ pub enum Commands { #[cfg(feature = "plugin")] #[clap(subcommand)] Plugin(plugin::Plugin), + + /// Handles parsing of linker arguments for linker-based systems + /// such as Manganis and binary patching. + Link(link::LinkCommand), } impl Display for Commands { @@ -100,6 +105,7 @@ impl Display for Commands { Commands::Autoformat(_) => write!(f, "fmt"), Commands::Check(_) => write!(f, "check"), Commands::Bundle(_) => write!(f, "bundle"), + Commands::Link(_) => write!(f, "link"), #[cfg(feature = "plugin")] Commands::Plugin(_) => write!(f, "plugin"), diff --git a/packages/cli/src/cli/plugin.rs b/packages/cli/src/cli/plugin.rs index 5be2364f7..ccff887cd 100644 --- a/packages/cli/src/cli/plugin.rs +++ b/packages/cli/src/cli/plugin.rs @@ -15,7 +15,7 @@ pub enum Plugin { } impl Plugin { - pub async fn plugin(self) -> Result<()> { + pub fn plugin(self) -> Result<()> { match self { Plugin::List {} => { for item in crate::plugin::PluginManager::plugin_list() { diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index e3257f34a..f5ce651ed 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -14,7 +14,7 @@ pub struct Serve { } impl Serve { - pub async fn serve(self, bin: Option) -> Result<()> { + pub fn serve(self, bin: Option) -> Result<()> { let mut crate_config = dioxus_cli_config::CrateConfig::new(bin)?; let serve_cfg = self.serve.clone(); @@ -65,10 +65,10 @@ impl Serve { // start the develop server use server::{desktop, fullstack, web}; match platform { - Platform::Web => web::startup(crate_config.clone(), &serve_cfg).await?, - Platform::Desktop => desktop::startup(crate_config.clone(), &serve_cfg).await?, + Platform::Web => web::startup(crate_config.clone(), &serve_cfg)?, + Platform::Desktop => desktop::startup(crate_config.clone(), &serve_cfg)?, Platform::Fullstack | Platform::StaticGeneration => { - fullstack::startup(crate_config.clone(), &serve_cfg).await? + fullstack::startup(crate_config.clone(), &serve_cfg)? } _ => unreachable!(), } diff --git a/packages/cli/src/lib.rs b/packages/cli/src/lib.rs index 37d234aa8..b4df0f8e1 100644 --- a/packages/cli/src/lib.rs +++ b/packages/cli/src/lib.rs @@ -2,7 +2,7 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -mod assets; +pub mod assets; pub mod builder; pub mod server; pub mod tools; diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index eb4fb5519..4232d0e51 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -10,8 +10,7 @@ use Commands::*; const LOG_ENV: &str = "DIOXUS_LOG"; -#[tokio::main] -async fn main() -> anyhow::Result<()> { +fn main() -> anyhow::Result<()> { let args = Cli::parse(); // If {LOG_ENV} is set, default to env, otherwise filter to cli @@ -40,19 +39,17 @@ async fn main() -> anyhow::Result<()> { .context(error_wrapper("Configuring new project failed")), #[cfg(feature = "plugin")] - Plugin(opts) => opts - .plugin() - .await - .context(error_wrapper("Error with plugin")), + Plugin(opts) => opts.plugin().context(error_wrapper("Error with plugin")), Autoformat(opts) => opts .autoformat() .context(error_wrapper("Error autoformatting RSX")), - Check(opts) => opts - .check() - .await - .context(error_wrapper("Error checking RSX")), + Check(opts) => opts.check().context(error_wrapper("Error checking RSX")), + + Link(opts) => opts + .link() + .context(error_wrapper("Error with linker passthrough")), action => { let bin = get_bin(args.bin)?; @@ -81,7 +78,6 @@ async fn main() -> anyhow::Result<()> { Serve(opts) => opts .serve(Some(bin.clone())) - .await .context(error_wrapper("Serving project failed")), Bundle(opts) => opts diff --git a/packages/cli/src/server/desktop/mod.rs b/packages/cli/src/server/desktop/mod.rs index 0d6e6682e..700434947 100644 --- a/packages/cli/src/server/desktop/mod.rs +++ b/packages/cli/src/server/desktop/mod.rs @@ -23,11 +23,11 @@ use crate::plugin::PluginManager; use super::HotReloadState; -pub async fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> { - startup_with_platform::(config, serve).await +pub fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> { + startup_with_platform::(config, serve) } -pub(crate) async fn startup_with_platform( +pub(crate) fn startup_with_platform( config: CrateConfig, serve_cfg: &ConfigOptsServe, ) -> Result<()> { @@ -54,7 +54,7 @@ pub(crate) async fn startup_with_platform( file_map, }; - serve::

(config, serve_cfg, hot_reload_state).await?; + serve::

(config, serve_cfg, hot_reload_state)?; Ok(()) } @@ -70,53 +70,55 @@ fn set_ctrl_c(config: &CrateConfig) { } /// Start the server without hot reload -async fn serve( +fn serve( config: CrateConfig, serve: &ConfigOptsServe, hot_reload_state: HotReloadState, ) -> Result<()> { - let hot_reload: tokio::task::JoinHandle> = tokio::spawn({ - let hot_reload_state = hot_reload_state.clone(); - async move { - match hot_reload_state.file_map.clone() { - Some(file_map) => { - // The open interprocess sockets - start_desktop_hot_reload(hot_reload_state, file_map).await?; - } - None => { - std::future::pending::<()>().await; - } - } - Ok(()) - } - }); - let platform = RwLock::new(P::start(&config, serve, Vec::new())?); - tracing::info!("🚀 Starting development server..."); - - // We got to own watcher so that it exists for the duration of serve - // Otherwise full reload won't work. - let _watcher = setup_file_watcher( - { - let config = config.clone(); - let serve = serve.clone(); - move || { - platform - .write() - .unwrap() - .rebuild(&config, &serve, Vec::new()) + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async move { + let hot_reload: tokio::task::JoinHandle> = tokio::spawn({ + let hot_reload_state = hot_reload_state.clone(); + async move { + match hot_reload_state.file_map.clone() { + Some(file_map) => { + // The open interprocess sockets + start_desktop_hot_reload(hot_reload_state, file_map).await?; + } + None => { + std::future::pending::<()>().await; + } + } + Ok(()) } - }, - &config, - None, - hot_reload_state, - ) - .await?; + }); - hot_reload.await.unwrap()?; + tracing::info!("🚀 Starting development server..."); - Ok(()) + // We got to own watcher so that it exists for the duration of serve + // Otherwise full reload won't work. + let _watcher = setup_file_watcher( + { + let config = config.clone(); + let serve = serve.clone(); + move || { + platform + .write() + .unwrap() + .rebuild(&config, &serve, Vec::new()) + } + }, + &config, + None, + hot_reload_state, + ) + .await?; + + hot_reload.await.unwrap()?; + Ok(()) + }) } async fn start_desktop_hot_reload( diff --git a/packages/cli/src/server/fullstack/mod.rs b/packages/cli/src/server/fullstack/mod.rs index 6fedcda81..1614505e6 100644 --- a/packages/cli/src/server/fullstack/mod.rs +++ b/packages/cli/src/server/fullstack/mod.rs @@ -36,8 +36,8 @@ pub fn server_rust_flags(build: &ConfigOptsBuild) -> String { rust_flags(build, SERVER_RUST_FLAGS) } -pub async fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> { - desktop::startup_with_platform::(config, serve).await +pub fn startup(config: CrateConfig, serve: &ConfigOptsServe) -> Result<()> { + desktop::startup_with_platform::(config, serve) } fn start_web_build_thread( diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 9c07a7b55..a82fb6937 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -22,7 +22,7 @@ use server::*; use super::HotReloadState; -pub async fn startup(config: CrateConfig, serve_cfg: &ConfigOptsServe) -> Result<()> { +pub fn startup(config: CrateConfig, serve_cfg: &ConfigOptsServe) -> Result<()> { set_ctrlc_handler(&config); let ip = serve_cfg @@ -33,11 +33,11 @@ pub async fn startup(config: CrateConfig, serve_cfg: &ConfigOptsServe) -> Result let hot_reload_state = build_hotreload_filemap(&config); - serve(ip, config, hot_reload_state, serve_cfg).await + serve(ip, config, hot_reload_state, serve_cfg) } /// Start the server without hot reload -pub async fn serve( +pub fn serve( ip: IpAddr, config: CrateConfig, hot_reload_state: HotReloadState, @@ -55,42 +55,45 @@ pub async fn serve( tracing::info!("🚀 Starting development server..."); - // We got to own watcher so that it exists for the duration of serve - // Otherwise full reload won't work. - let _watcher = setup_file_watcher( - { - let config = config.clone(); - let hot_reload_state = hot_reload_state.clone(); - move || build(&config, &hot_reload_state, skip_assets) - }, - &config, - Some(WebServerInfo { ip, port }), - hot_reload_state.clone(), - ) - .await?; + let rt = tokio::runtime::Runtime::new().unwrap(); + rt.block_on(async move { + // We got to own watcher so that it exists for the duration of serve + // Otherwise full reload won't work. + let _watcher = setup_file_watcher( + { + let config = config.clone(); + let hot_reload_state = hot_reload_state.clone(); + move || build(&config, &hot_reload_state, skip_assets) + }, + &config, + Some(WebServerInfo { ip, port }), + hot_reload_state.clone(), + ) + .await?; - // HTTPS - // Before console info so it can stop if mkcert isn't installed or fails - let rustls_config = get_rustls(&config).await?; + // HTTPS + // Before console info so it can stop if mkcert isn't installed or fails + let rustls_config = get_rustls(&config).await?; - // Print serve info - print_console_info( - &config, - PrettierOptions { - changed: vec![], - warnings: first_build_result.warnings, - elapsed_time: first_build_result.elapsed_time, - }, - Some(WebServerInfo { ip, port }), - ); + // Print serve info + print_console_info( + &config, + PrettierOptions { + changed: vec![], + warnings: first_build_result.warnings, + elapsed_time: first_build_result.elapsed_time, + }, + Some(WebServerInfo { ip, port }), + ); - // Router - let router = setup_router(config.clone(), hot_reload_state).await?; + // Router + let router = setup_router(config.clone(), hot_reload_state).await?; - // Start server - start_server(ip, port, router, opts.open, rustls_config, &config).await?; + // Start server + start_server(ip, port, router, opts.open, rustls_config, &config).await?; - Ok(()) + Ok(()) + }) } /// Starts dx serve with no hot reload