diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs index 85d052cb5..f6dba4767 100644 --- a/packages/cli-config/src/config.rs +++ b/packages/cli-config/src/config.rs @@ -7,12 +7,17 @@ use std::path::PathBuf; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)] #[cfg_attr(feature = "cli", derive(clap::ValueEnum))] pub enum Platform { + /// Targeting the web platform using WASM #[cfg_attr(feature = "cli", clap(name = "web"))] #[serde(rename = "web")] Web, + + /// Targeting the desktop platform using Tao/Wry-based webview #[cfg_attr(feature = "cli", clap(name = "desktop"))] #[serde(rename = "desktop")] Desktop, + + /// Targeting the server platform using Axum and Dioxus-Fullstack #[cfg_attr(feature = "cli", clap(name = "fullstack"))] #[serde(rename = "fullstack")] Fullstack, @@ -536,6 +541,34 @@ impl CrateConfig { self.cargo_args = cargo_args; self } + + pub fn add_features(&mut self, feature: Vec) -> &mut Self { + if let Some(features) = &mut self.features { + features.extend(feature); + } else { + self.features = Some(feature); + } + self + } + + #[cfg(feature = "cli")] + pub fn extend_with_platform(&mut self, platform: Platform) -> &mut Self { + let manifest = &self.manifest; + let features = match platform { + Platform::Web if manifest.features.contains_key("web") => { + vec!["web".to_string()] + } + Platform::Desktop if manifest.features.contains_key("desktop") => { + vec!["desktop".to_string()] + } + _ => { + // fullstack has its own feature insertion - we use a different featureset for the client and server + vec![] + } + }; + self.add_features(features); + self + } } fn true_bool() -> bool { diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 10853647b..e10d2c270 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["react", "gui", "cli", "dioxus", "wasm"] [dependencies] # cli core -clap = { version = "4.2", features = ["derive"] } +clap = { version = "4.2", features = ["derive", "cargo"] } thiserror = { workspace = true } wasm-bindgen-cli-support = "0.2" colored = "2.0.0" diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index cb91941e5..9a2c0ebb5 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -15,6 +15,7 @@ use std::{ io::Read, panic, path::PathBuf, + process::Command, time::Duration, }; use wasm_bindgen_cli_support::Bindgen; @@ -98,16 +99,17 @@ pub fn build_web( // [1] Build the .wasm module log::info!("🚅 Running build command..."); - let wasm_check_command = std::process::Command::new("rustup") - .args(["show"]) - .output()?; - - let wasm_check_output = String::from_utf8(wasm_check_command.stdout).unwrap(); - if !wasm_check_output.contains("wasm32-unknown-unknown") { - log::info!("wasm32-unknown-unknown target not detected, installing.."); - let _ = std::process::Command::new("rustup") - .args(["target", "add", "wasm32-unknown-unknown"]) - .output()?; + // If the user has rustup, we can check if the wasm32-unknown-unknown target is installed + // Otherwise we can just assume it is installed - which i snot great... + // Eventually we can poke at the errors and let the user know they need to install the target + if let Ok(wasm_check_command) = Command::new("rustup").args(["show"]).output() { + let wasm_check_output = String::from_utf8(wasm_check_command.stdout).unwrap(); + if !wasm_check_output.contains("wasm32-unknown-unknown") { + log::info!("wasm32-unknown-unknown target not detected, installing.."); + let _ = Command::new("rustup") + .args(["target", "add", "wasm32-unknown-unknown"]) + .output()?; + } } let cmd = subprocess::Exec::cmd("cargo") @@ -333,6 +335,12 @@ pub fn build_desktop( let _manganis_support = ManganisSupportGuard::default(); let _guard = AssetConfigDropGuard::new(); + // set the asset dir via cli args + env::set_var( + "DIOXUS_ASSET_DIR", + config.asset_dir().canonicalize().unwrap(), + ); + let mut cmd = subprocess::Exec::cmd("cargo") .set_rust_flags(rust_flags) .env("CARGO_TARGET_DIR", &config.target_dir) diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index d0139c322..365a4f572 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -50,6 +50,7 @@ impl Build { } crate_config.set_cargo_args(self.build.cargo_args.clone()); + crate_config.extend_with_platform(platform); // #[cfg(feature = "plugin")] // let _ = crate::plugin::PluginManager::on_build_start(&crate_config, &platform); diff --git a/packages/cli/src/cli/bundle.rs b/packages/cli/src/cli/bundle.rs index 44c8548b3..85c21cd21 100644 --- a/packages/cli/src/cli/bundle.rs +++ b/packages/cli/src/cli/bundle.rs @@ -82,6 +82,9 @@ impl Bundle { } crate_config.set_cargo_args(self.build.cargo_args); + if let Some(platform) = self.build.platform { + crate_config.extend_with_platform(platform); + } // build the desktop app // Since the `bundle()` function is only run for the desktop platform, diff --git a/packages/cli/src/cli/cfg.rs b/packages/cli/src/cli/cfg.rs index ec352d55e..daa8ad713 100644 --- a/packages/cli/src/cli/cfg.rs +++ b/packages/cli/src/cli/cfg.rs @@ -178,7 +178,7 @@ pub struct ConfigOptsBundle { /// Build platform: support Web & Desktop [default: "default_platform"] #[clap(long)] - pub platform: Option, + pub platform: Option, /// Space separated list of features to activate #[clap(long)] diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index a72fc19e6..1ba985c13 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -60,6 +60,7 @@ impl Serve { } let platform = platform.unwrap_or(crate_config.dioxus_config.application.default_platform); + crate_config.extend_with_platform(platform); // start the develop server use server::{desktop, fullstack, web}; diff --git a/packages/cli/src/lib.rs b/packages/cli/src/lib.rs index 191c65008..5c904d7ba 100644 --- a/packages/cli/src/lib.rs +++ b/packages/cli/src/lib.rs @@ -2,8 +2,6 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -pub const DIOXUS_CLI_VERSION: &str = "0.4.1"; - mod assets; pub mod builder; pub mod server; diff --git a/packages/cli/src/server/output.rs b/packages/cli/src/server/output.rs index 5db24f512..feb3aad93 100644 --- a/packages/cli/src/server/output.rs +++ b/packages/cli/src/server/output.rs @@ -46,7 +46,7 @@ pub fn print_console_info( let custom_html_file = if crate_root.join("index.html").is_file() { "Custom [index.html]" } else { - "Default" + "None" }; let url_rewrite = if config.dioxus_config.web.watcher.index_on_404 { "True" @@ -58,9 +58,9 @@ pub fn print_console_info( if options.changed.is_empty() { println!( - "{} @ v{} [{}] \n", + "{} @ v{} [{}]", "Dioxus".bold().green(), - crate::DIOXUS_CLI_VERSION, + clap::crate_version!(), chrono::Local::now().format("%H:%M:%S").to_string().dimmed() ); } else { @@ -79,40 +79,50 @@ pub fn print_console_info( if let Some(WebServerInfo { ip, port }) = web_info { if config.dioxus_config.web.https.enabled == Some(true) { println!( - "\t> Local : {}", + " > Local address: {}", format!("https://localhost:{}/", port).blue() ); println!( - "\t> Network : {}", + " > Network address: {}", format!("https://{}:{}/", ip, port).blue() ); - println!("\t> HTTPS : {}", "Enabled".to_string().green()); + println!(" > HTTPS: {}", "Enabled".to_string().green()); } else { println!( - "\t> Local : {}", + " > Local address: {}", format!("http://localhost:{}/", port).blue() ); println!( - "\t> Network : {}", + " > Network address: {}", format!("http://{}:{}/", ip, port).blue() ); - println!("\t> HTTPS : {}", "Disabled".to_string().red()); + println!(" > HTTPS status: {}", "Disabled".to_string().red()); } } println!(); - println!("\t> Profile : {}", profile.green()); - println!("\t> Hot Reload : {}", hot_reload.cyan()); + + println!(" > Hot Reload Mode: {}", hot_reload.cyan()); if !proxies.is_empty() { - println!("\t> Proxies :"); + println!(" > Proxies :"); for proxy in proxies { - println!("\t\t- {}", proxy.backend.blue()); + println!(" - {}", proxy.backend.blue()); } } - println!("\t> Index Template : {}", custom_html_file.green()); - println!("\t> URL Rewrite [index_on_404] : {}", url_rewrite.purple()); + println!(" > Custom index.html: {}", custom_html_file.green()); + println!(" > Serve index.html on 404: {}", url_rewrite.purple()); println!(); println!( - "\t> Build Time Use : {} millis", + " > Build Features: [ {} ]", + config + .features + .clone() + .unwrap_or_default() + .join(", ") + .green() + ); + println!(" > Build Profile: {}", profile.green()); + println!( + " > Build took: {} millis", options.elapsed_time.to_string().green().bold() ); println!(); diff --git a/packages/desktop/src/app.rs b/packages/desktop/src/app.rs index 6f5abd279..9c0719d49 100644 --- a/packages/desktop/src/app.rs +++ b/packages/desktop/src/app.rs @@ -278,8 +278,11 @@ impl App { self.control_flow = ControlFlow::Exit; } - // todo: enable asset hotreloading in desktop - dioxus_hot_reload::HotReloadMsg::UpdateAsset(_) => {} + dioxus_hot_reload::HotReloadMsg::UpdateAsset(_) => { + for webview in self.webviews.values_mut() { + webview.kick_stylsheets(); + } + } } } diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 89b948f0e..7d2c1a8a1 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -221,7 +221,10 @@ fn get_asset_root() -> Option { // If running under cargo, there's no bundle! // There might be a smarter/more resilient way of doing this if std::env::var_os("CARGO").is_some() { - return None; + return dioxus_cli_config::CURRENT_CONFIG + .as_ref() + .map(|c| c.out_dir()) + .ok(); } #[cfg(target_os = "macos")] diff --git a/packages/desktop/src/webview.rs b/packages/desktop/src/webview.rs index ae3d48260..49edf6758 100644 --- a/packages/desktop/src/webview.rs +++ b/packages/desktop/src/webview.rs @@ -221,4 +221,12 @@ impl WebviewInstance { self.desktop_context.send_edits(); } } + + pub fn kick_stylsheets(&self) { + // run eval in the webview to kick the stylesheets by appending a query string + // we should do something less clunky than this + _ = self.desktop_context + .webview + .evaluate_script("document.querySelectorAll('link[rel=\"stylesheet\"]').forEach((el) => el.href = el.href + \"?\" + Math.random());"); + } }