From 8b4e0b3e07f831bc7f0576b4c0e9a3cde304abb1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 8 Aug 2023 15:33:48 -0700 Subject: [PATCH 01/17] Use serde default instead of options in the CLI --- packages/cli/src/builder.rs | 31 ++------- packages/cli/src/cli/build.rs | 9 +-- packages/cli/src/cli/clean.rs | 6 +- packages/cli/src/cli/serve.rs | 11 +-- packages/cli/src/config.rs | 107 ++++++++++++++++++++--------- packages/cli/src/server/mod.rs | 21 +----- packages/cli/src/server/output.rs | 20 ++---- packages/cli/src/server/web/mod.rs | 17 +---- 8 files changed, 100 insertions(+), 122 deletions(-) diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 3fa8e78181..6dca9e7794 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -130,7 +130,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { } // check binaryen:wasm-opt tool - let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default(); + let dioxus_tools = dioxus_config.application.tools.clone(); if dioxus_tools.contains_key("binaryen") { let info = dioxus_tools.get("binaryen").unwrap(); let binaryen = crate::tools::Tool::Binaryen; @@ -346,13 +346,7 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result String { let mut script_list = resouces.script.unwrap_or_default(); if serve { - let mut dev_style = resouces.dev.style.clone().unwrap_or_default(); - let mut dev_script = resouces.dev.script.unwrap_or_default(); + let mut dev_style = resouces.dev.style.clone(); + let mut dev_script = resouces.dev.script; style_list.append(&mut dev_style); script_list.append(&mut dev_script); } @@ -459,13 +453,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { &style.to_str().unwrap(), )) } - if config - .application - .tools - .clone() - .unwrap_or_default() - .contains_key("tailwindcss") - { + if config.application.tools.clone().contains_key("tailwindcss") { style_str.push_str("\n"); } @@ -516,12 +504,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { ); } - let title = config - .web - .app - .title - .clone() - .unwrap_or_else(|| "dioxus | ⛺".into()); + let title = config.web.app.title.clone(); replace_or_insert_before("{app_title}", &title, " Result> { let mut result = vec![]; let dioxus_config = &config.dioxus_config; - let dioxus_tools = dioxus_config.application.tools.clone().unwrap_or_default(); + let dioxus_tools = dioxus_config.application.tools.clone(); // check sass tool state let sass = Tool::Sass; diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 3053a6e5af..93136aa19a 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -54,14 +54,7 @@ impl Build { let mut file = std::fs::File::create( crate_config .crate_dir - .join( - crate_config - .dioxus_config - .application - .out_dir - .clone() - .unwrap_or_else(|| PathBuf::from("dist")), - ) + .join(crate_config.dioxus_config.application.out_dir.clone()) .join("index.html"), )?; file.write_all(temp.as_bytes())?; diff --git a/packages/cli/src/cli/clean.rs b/packages/cli/src/cli/clean.rs index 5fed1e1a62..09fb214690 100644 --- a/packages/cli/src/cli/clean.rs +++ b/packages/cli/src/cli/clean.rs @@ -19,11 +19,7 @@ impl Clean { return custom_error!("Cargo clean failed."); } - let out_dir = crate_config - .dioxus_config - .application - .out_dir - .unwrap_or_else(|| PathBuf::from("dist")); + let out_dir = crate_config.dioxus_config.application.out_dir; if crate_config.crate_dir.join(&out_dir).is_dir() { remove_dir_all(crate_config.crate_dir.join(&out_dir))?; } diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index 433d611b73..2681c4a5fa 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -58,14 +58,9 @@ impl Serve { pub fn regen_dev_page(crate_config: &CrateConfig) -> Result<()> { let serve_html = gen_page(&crate_config.dioxus_config, true); - let dist_path = crate_config.crate_dir.join( - crate_config - .dioxus_config - .application - .out_dir - .clone() - .unwrap_or_else(|| PathBuf::from("dist")), - ); + let dist_path = crate_config + .crate_dir + .join(crate_config.dioxus_config.application.out_dir.clone()); if !dist_path.is_dir() { create_dir_all(&dist_path)?; } diff --git a/packages/cli/src/config.rs b/packages/cli/src/config.rs index 2e499451ff..2fc9f96ce4 100644 --- a/packages/cli/src/config.rs +++ b/packages/cli/src/config.rs @@ -86,33 +86,33 @@ fn acquire_dioxus_toml(dir: &Path) -> Option { impl Default for DioxusConfig { fn default() -> Self { - let name = "name"; + let name = default_name(); Self { application: ApplicationConfig { - name: name.into(), - default_platform: Platform::Web, - out_dir: Some(PathBuf::from("dist")), - asset_dir: Some(PathBuf::from("public")), + name: name.clone(), + default_platform: default_platform(), + out_dir: out_dir_default(), + asset_dir: asset_dir_default(), - tools: None, + tools: Default::default(), sub_package: None, }, web: WebConfig { app: WebAppConfig { - title: Some("dioxus | ⛺".into()), + title: default_title(), base_path: None, }, - proxy: Some(vec![]), + proxy: vec![], watcher: WebWatcherConfig { - watch_path: Some(vec![PathBuf::from("src")]), - reload_html: Some(false), - index_on_404: Some(true), + watch_path: watch_path_default(), + reload_html: false, + index_on_404: true, }, resource: WebResourceConfig { dev: WebDevResourceConfig { - style: Some(vec![]), - script: Some(vec![]), + style: vec![], + script: vec![], }, style: Some(vec![]), script: Some(vec![]), @@ -136,20 +136,44 @@ impl Default for DioxusConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationConfig { + #[serde(default = "default_name")] pub name: String, + #[serde(default = "default_platform")] pub default_platform: Platform, - pub out_dir: Option, - pub asset_dir: Option, + #[serde(default = "out_dir_default")] + pub out_dir: PathBuf, + #[serde(default = "asset_dir_default")] + pub asset_dir: PathBuf, - pub tools: Option>, + #[serde(default)] + pub tools: HashMap, + #[serde(default)] pub sub_package: Option, } +fn default_name() -> String { + "name".into() +} + +fn default_platform() -> Platform { + Platform::Web +} + +fn asset_dir_default() -> PathBuf { + PathBuf::from("public") +} + +fn out_dir_default() -> PathBuf { + PathBuf::from("dist") +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebConfig { + #[serde(default)] pub app: WebAppConfig, - pub proxy: Option>, + #[serde(default)] + pub proxy: Vec, pub watcher: WebWatcherConfig, pub resource: WebResourceConfig, #[serde(default)] @@ -158,10 +182,24 @@ pub struct WebConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebAppConfig { - pub title: Option, + #[serde(default = "default_title")] + pub title: String, pub base_path: Option, } +impl Default for WebAppConfig { + fn default() -> Self { + Self { + title: default_title(), + base_path: None, + } + } +} + +fn default_title() -> String { + "dioxus | ⛺".into() +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebProxyConfig { pub backend: String, @@ -169,9 +207,16 @@ pub struct WebProxyConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebWatcherConfig { - pub watch_path: Option>, - pub reload_html: Option, - pub index_on_404: Option, + #[serde(default = "watch_path_default")] + pub watch_path: Vec, + #[serde(default)] + pub reload_html: bool, + #[serde(default = "true_bool")] + pub index_on_404: bool, +} + +fn watch_path_default() -> Vec { + vec![PathBuf::from("src")] } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -183,8 +228,10 @@ pub struct WebResourceConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebDevResourceConfig { - pub style: Option>, - pub script: Option>, + #[serde(default)] + pub style: Vec, + #[serde(default)] + pub script: Vec, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -238,17 +285,11 @@ impl CrateConfig { let workspace_dir = meta.workspace_root; let target_dir = meta.target_directory; - let out_dir = match dioxus_config.application.out_dir { - Some(ref v) => crate_dir.join(v), - None => crate_dir.join("dist"), - }; + let out_dir = crate_dir.join(&dioxus_config.application.out_dir); let cargo_def = &crate_dir.join("Cargo.toml"); - let asset_dir = match dioxus_config.application.asset_dir { - Some(ref v) => crate_dir.join(v), - None => crate_dir.join("public"), - }; + let asset_dir = crate_dir.join(&dioxus_config.application.asset_dir); let manifest = cargo_toml::Manifest::from_path(cargo_def).unwrap(); @@ -577,3 +618,7 @@ impl Default for WebviewInstallMode { Self::OfflineInstaller { silent: false } } } + +fn true_bool() -> bool { + true +} diff --git a/packages/cli/src/server/mod.rs b/packages/cli/src/server/mod.rs index 19dc44b752..b0f3bc56d8 100644 --- a/packages/cli/src/server/mod.rs +++ b/packages/cli/src/server/mod.rs @@ -5,10 +5,7 @@ use dioxus_core::Template; use dioxus_html::HtmlCtx; use dioxus_rsx::hot_reload::*; use notify::{RecommendedWatcher, Watcher}; -use std::{ - path::PathBuf, - sync::{Arc, Mutex}, -}; +use std::sync::{Arc, Mutex}; use tokio::sync::broadcast::Sender; mod output; @@ -25,13 +22,7 @@ async fn setup_file_watcher Result + Send + 'static>( let mut last_update_time = chrono::Local::now().timestamp(); // file watcher: check file change - let allow_watch_path = config - .dioxus_config - .web - .watcher - .watch_path - .clone() - .unwrap_or_else(|| vec![PathBuf::from("src")]); + let allow_watch_path = config.dioxus_config.web.watcher.watch_path.clone(); let watcher_config = config.clone(); let mut watcher = notify::recommended_watcher(move |info: notify::Result| { @@ -87,13 +78,7 @@ async fn setup_file_watcher_hot_reload Result + Send + ' web_info: Option, ) -> Result { // file watcher: check file change - let allow_watch_path = config - .dioxus_config - .web - .watcher - .watch_path - .clone() - .unwrap_or_else(|| vec![PathBuf::from("src")]); + let allow_watch_path = config.dioxus_config.web.watcher.watch_path.clone(); let watcher_config = config.clone(); let mut last_update_time = chrono::Local::now().timestamp(); diff --git a/packages/cli/src/server/output.rs b/packages/cli/src/server/output.rs index ce0f550647..68582f7422 100644 --- a/packages/cli/src/server/output.rs +++ b/packages/cli/src/server/output.rs @@ -46,19 +46,13 @@ pub fn print_console_info( } else { "Default" }; - let url_rewrite = if config - .dioxus_config - .web - .watcher - .index_on_404 - .unwrap_or(false) - { + let url_rewrite = if config.dioxus_config.web.watcher.index_on_404 { "True" } else { "False" }; - let proxies = config.dioxus_config.web.proxy.as_ref(); + let proxies = &config.dioxus_config.web.proxy; if options.changed.is_empty() { println!( @@ -106,12 +100,10 @@ pub fn print_console_info( println!(); println!("\t> Profile : {}", profile.green()); println!("\t> Hot Reload : {}", hot_reload.cyan()); - if let Some(proxies) = proxies { - if !proxies.is_empty() { - println!("\t> Proxies :"); - for proxy in proxies { - println!("\t\t- {}", proxy.backend.blue()); - } + if !proxies.is_empty() { + println!("\t> Proxies :"); + for proxy in proxies { + println!("\t\t- {}", proxy.backend.blue()); } } println!("\t> Index Template : {}", custom_html_file.green()); diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index e08d2297a6..768236f5d2 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -322,12 +322,7 @@ async fn setup_router( .override_response_header(HeaderName::from_static("cross-origin-opener-policy"), coop) .and_then( move |response: Response| async move { - let response = if file_service_config - .dioxus_config - .web - .watcher - .index_on_404 - .unwrap_or(false) + let response = if file_service_config.dioxus_config.web.watcher.index_on_404 && response.status() == StatusCode::NOT_FOUND { let body = Full::from( @@ -359,7 +354,7 @@ async fn setup_router( let mut router = Router::new().route("/_dioxus/ws", get(ws_handler)); // Setup proxy - for proxy_config in config.dioxus_config.web.proxy.unwrap_or_default() { + for proxy_config in config.dioxus_config.web.proxy { router = proxy::add_proxy(router, &proxy_config)?; } @@ -476,13 +471,7 @@ fn build(config: &CrateConfig, reload_tx: &Sender<()>) -> Result { let result = builder::build(config, true)?; // change the websocket reload state to true; // the page will auto-reload. - if config - .dioxus_config - .web - .watcher - .reload_html - .unwrap_or(false) - { + if config.dioxus_config.web.watcher.reload_html { let _ = Serve::regen_dev_page(config); } let _ = reload_tx.send(()); From 8d1c17ba7dcb2da08379cbcfcbfdf2d20b906849 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 9 Aug 2023 11:10:41 -0700 Subject: [PATCH 02/17] fix clippy --- packages/cli/src/config.rs | 2 +- packages/core/tests/suspense.rs | 2 +- packages/desktop/src/protocol.rs | 9 +++++++-- packages/html/src/eval.rs | 2 +- packages/native-core/src/real_dom.rs | 1 - packages/rsx/src/lib.rs | 10 ++-------- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/config.rs b/packages/cli/src/config.rs index 2fc9f96ce4..267a7f2a2e 100644 --- a/packages/cli/src/config.rs +++ b/packages/cli/src/config.rs @@ -126,7 +126,7 @@ impl Default for DioxusConfig { }, bundle: BundleConfig { identifier: Some(format!("io.github.{name}")), - publisher: Some(name.into()), + publisher: Some(name), ..Default::default() }, plugin: toml::Value::Table(toml::map::Map::new()), diff --git a/packages/core/tests/suspense.rs b/packages/core/tests/suspense.rs index 7b25164478..abce7f8a65 100644 --- a/packages/core/tests/suspense.rs +++ b/packages/core/tests/suspense.rs @@ -36,7 +36,7 @@ fn suspended_child(cx: Scope) -> Element { cx.spawn(async move { val += 1; }); - return cx.suspend()?; + cx.suspend()?; } render!("child") diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 89ce50a489..53652f82f2 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -158,8 +158,13 @@ fn get_mime_from_path(trimmed: &Path) -> Result<&'static str> { } let res = match infer::get_from_path(trimmed)?.map(|f| f.mime_type()) { - Some(t) if t == "text/plain" => get_mime_by_ext(trimmed), - Some(f) => f, + Some(f) => { + if f == "text/plain" { + get_mime_by_ext(trimmed) + } else { + f + } + } None => get_mime_by_ext(trimmed), }; diff --git a/packages/html/src/eval.rs b/packages/html/src/eval.rs index b39eef805d..c90f5125be 100644 --- a/packages/html/src/eval.rs +++ b/packages/html/src/eval.rs @@ -42,7 +42,7 @@ pub fn use_eval(cx: &ScopeState) -> &EvalCreator { Rc::new(move |script: &str| { eval_provider .new_evaluator(script.to_string()) - .map(|evaluator| UseEval::new(evaluator)) + .map(UseEval::new) }) as Rc Result> }) } diff --git a/packages/native-core/src/real_dom.rs b/packages/native-core/src/real_dom.rs index 44c378ddfb..b520b2de11 100644 --- a/packages/native-core/src/real_dom.rs +++ b/packages/native-core/src/real_dom.rs @@ -446,7 +446,6 @@ impl RealDom { drop(tree); children.reverse(); if let Some(node) = self.get_mut(id) { - let node = node; f(node); stack.extend(children.iter()); } diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index 1f01fcd722..783dd3322f 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -288,10 +288,7 @@ impl DynamicMapping { let idx = self.last_attribute_idx; self.last_attribute_idx += 1; - self.attribute_to_idx - .entry(attr) - .or_insert_with(Vec::new) - .push(idx); + self.attribute_to_idx.entry(attr).or_default().push(idx); idx } @@ -300,10 +297,7 @@ impl DynamicMapping { let idx = self.last_element_idx; self.last_element_idx += 1; - self.node_to_idx - .entry(node) - .or_insert_with(Vec::new) - .push(idx); + self.node_to_idx.entry(node).or_default().push(idx); idx } From 4691046e238e850644193ba2ea4232a7a60f9ac9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 17 Sep 2023 19:01:20 -0500 Subject: [PATCH 03/17] fix formatting --- packages/fullstack/src/adapters/warp_adapter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fullstack/src/adapters/warp_adapter.rs b/packages/fullstack/src/adapters/warp_adapter.rs index 5afcb5077d..316d70e56b 100644 --- a/packages/fullstack/src/adapters/warp_adapter.rs +++ b/packages/fullstack/src/adapters/warp_adapter.rs @@ -143,7 +143,7 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R let req = warp::hyper::Request::from_parts(parts, bytes.into()); service.run(req).await.map_err(|err| { tracing::error!("Server function error: {}", err); - + struct WarpServerFnError(String); impl std::fmt::Debug for WarpServerFnError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -152,7 +152,7 @@ pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl R } impl warp::reject::Reject for WarpServerFnError {} - + warp::reject::custom(WarpServerFnError(err.to_string())) }) } From 8a2d170d9622cb466f034f46ba3123e92fe7464c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 8 Nov 2023 12:48:25 -0600 Subject: [PATCH 04/17] pull out the CLI config data into a separate library --- Cargo.toml | 2 + packages/cli-config/.gitignore | 4 + packages/cli-config/Cargo.toml | 102 ++++ packages/cli-config/README.md | 5 + packages/cli-config/src/assets/dioxus.toml | 74 +++ packages/{cli => cli-config}/src/cargo.rs | 43 +- packages/cli-config/src/config.rs | 658 +++++++++++++++++++++ packages/cli-config/src/lib.rs | 9 + packages/cli/Cargo.toml | 1 + packages/cli/src/builder.rs | 3 +- packages/cli/src/cli/build.rs | 2 +- packages/cli/src/cli/cfg.rs | 13 +- packages/cli/src/cli/config.rs | 4 +- packages/cli/src/cli/serve.rs | 6 +- packages/cli/src/config.rs | 9 +- packages/cli/src/error.rs | 14 + packages/cli/src/lib.rs | 3 - packages/cli/src/server/output.rs | 3 +- 18 files changed, 919 insertions(+), 36 deletions(-) create mode 100644 packages/cli-config/.gitignore create mode 100644 packages/cli-config/Cargo.toml create mode 100644 packages/cli-config/README.md create mode 100644 packages/cli-config/src/assets/dioxus.toml rename packages/{cli => cli-config}/src/cargo.rs (69%) create mode 100644 packages/cli-config/src/config.rs create mode 100644 packages/cli-config/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index d687d74d00..c615e2e42b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "packages/dioxus", "packages/core", "packages/cli", + "packages/cli-config", "packages/core-macro", "packages/router-macro", "packages/extension", @@ -78,6 +79,7 @@ dioxus-native-core-macro = { path = "packages/native-core-macro", version = "0.4 rsx-rosetta = { path = "packages/rsx-rosetta", version = "0.4.0" } dioxus-signals = { path = "packages/signals" } generational-box = { path = "packages/generational-box" } +dioxus-cli-config = { path = "packages/cli-config", version = "0.4.1" } dioxus-hot-reload = { path = "packages/hot-reload", version = "0.4.0" } dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" } dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" } diff --git a/packages/cli-config/.gitignore b/packages/cli-config/.gitignore new file mode 100644 index 0000000000..6700b1332d --- /dev/null +++ b/packages/cli-config/.gitignore @@ -0,0 +1,4 @@ +/target +Cargo.lock +.DS_Store +.idea/ diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml new file mode 100644 index 0000000000..d89d411fd9 --- /dev/null +++ b/packages/cli-config/Cargo.toml @@ -0,0 +1,102 @@ +[package] +name = "dioxus-cli-config" +version = "0.4.1" +authors = ["Jonathan Kelley"] +edition = "2021" +description = "Configuration for the Dioxus CLI" +repository = "https://github.com/DioxusLabs/dioxus/" +license = "MIT OR Apache-2.0" +keywords = ["react", "gui", "cli", "dioxus", "wasm"] + +[dependencies] +# cli core +clap = { version = "4.2", features = ["derive"] } +thiserror = { workspace = true } +wasm-bindgen-cli-support = "0.2" +colored = "2.0.0" + +# features +log = "0.4.14" +fern = { version = "0.6.0", features = ["colored"] } +serde = { version = "1.0.136", features = ["derive"] } +serde_json = "1.0.79" +toml = "0.5.8" +fs_extra = "1.2.0" +cargo_toml = "0.16.0" +futures = "0.3.21" +notify = { version = "5.0.0-pre.16", features = ["serde"] } +html_parser = { workspace = true } +cargo_metadata = "0.15.0" +tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] } +atty = "0.2.14" +chrono = "0.4.19" +anyhow = "1.0.53" +hyper = "0.14.17" +hyper-rustls = "0.23.2" +indicatif = "0.17.5" +subprocess = "0.2.9" + +axum = { version = "0.5.1", features = ["ws", "headers"] } +axum-server = { version = "0.5.1", features = ["tls-rustls"] } +tower-http = { version = "0.2.2", features = ["full"] } +headers = "0.3.7" + +walkdir = "2" + +# tools download +dirs = "4.0.0" +reqwest = { version = "0.11", features = [ + "rustls-tls", + "stream", + "trust-dns", + "blocking", +] } +flate2 = "1.0.22" +tar = "0.4.38" +zip = "0.6.2" +tower = "0.4.12" +syn = { version = "2.0", features = ["full", "extra-traits"] } +lazy_static = "1.4.0" + +# plugin packages +mlua = { version = "0.8.1", features = [ + "lua54", + "vendored", + "async", + "send", + "macros", +], optional = true } +ctrlc = "3.2.3" +open = "4.1.0" +cargo-generate = "0.18" +toml_edit = "0.19.11" + +# bundling +tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"] } +tauri-utils = "=1.4.*" + +dioxus-autofmt = { workspace = true } +dioxus-check = { workspace = true } +rsx-rosetta = { workspace = true } +dioxus-rsx = { workspace = true } +dioxus-html = { workspace = true, features = ["hot-reload-context"] } +dioxus-core = { workspace = true, features = ["serialize"] } +dioxus-hot-reload = { workspace = true } +interprocess-docfix = { version = "1.2.2" } + +[features] +default = [] +plugin = ["mlua"] + +[[bin]] +path = "src/main.rs" +name = "dx" + +[dev-dependencies] +tempfile = "3.3" + +[package.metadata.binstall] +pkg-url = "{ repo }/releases/download/v{ version }/dx-{ target }{ archive-suffix }" + +[package.metadata.binstall.overrides.x86_64-pc-windows-msvc] +pkg-fmt = "zip" diff --git a/packages/cli-config/README.md b/packages/cli-config/README.md new file mode 100644 index 0000000000..ef24357136 --- /dev/null +++ b/packages/cli-config/README.md @@ -0,0 +1,5 @@ +
+

📦✨ Dioxus CLI Configuration

+
+ +The **dioxus-cli-config** contains the configuration for the **dioxus-cli**. diff --git a/packages/cli-config/src/assets/dioxus.toml b/packages/cli-config/src/assets/dioxus.toml new file mode 100644 index 0000000000..892a6cdf83 --- /dev/null +++ b/packages/cli-config/src/assets/dioxus.toml @@ -0,0 +1,74 @@ +[application] + +# dioxus project name +name = "{{project-name}}" + +# default platfrom +# you can also use `dx serve/build --platform XXX` to use other platform +# value: web | desktop +default_platform = "{{default-platform}}" + +# Web `build` & `serve` dist path +out_dir = "dist" + +# resource (static) file folder +asset_dir = "public" + +[web.app] + +# HTML title tag content +title = "Dioxus | An elegant GUI library for Rust" + +[web.watcher] + +index_on_404 = true + +watch_path = ["src", "examples"] + +# include `assets` in web platform +[web.resource] + +# CSS style file +style = [] + +# Javascript code file +script = [] + +[web.resource.dev] + +# Javascript code file +# serve: [dev-server] only +script = [] + +[application.plugins] + +available = true + +required = [] + +[bundler] +# Bundle identifier +identifier = "io.github.{{project-name}}" + +# Bundle publisher +publisher = "{{project-name}}" + +# Bundle icon +icon = ["icons/icon.png"] + +# Bundle resources +resources = ["public/*"] + +# Bundle copyright +copyright = "" + +# Bundle category +category = "Utility" + +# Bundle short description +short_description = "An amazing dioxus application." + +# Bundle long description +long_description = """ +An amazing dioxus application. +""" \ No newline at end of file diff --git a/packages/cli/src/cargo.rs b/packages/cli-config/src/cargo.rs similarity index 69% rename from packages/cli/src/cargo.rs rename to packages/cli-config/src/cargo.rs index b52fa4b09f..97e4040dbf 100644 --- a/packages/cli/src/cargo.rs +++ b/packages/cli-config/src/cargo.rs @@ -1,12 +1,33 @@ //! Utilities for working with cargo and rust files -use crate::error::{Error, Result}; +use std::error::Error; use std::{ - env, fs, + env, + fmt::{Display, Formatter}, + fs, path::{Path, PathBuf}, process::Command, str, }; +#[derive(Debug, Clone)] +pub struct CargoError { + msg: String, +} + +impl CargoError { + pub fn new(msg: String) -> Self { + Self { msg } + } +} + +impl Display for CargoError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "CargoError: {}", self.msg) + } +} + +impl Error for CargoError {} + /// How many parent folders are searched for a `Cargo.toml` const MAX_ANCESTORS: u32 = 10; @@ -19,7 +40,7 @@ pub struct Metadata { /// Returns the root of the crate that the command is run from /// /// If the command is run from the workspace root, this will return the top-level Cargo.toml -pub fn crate_root() -> Result { +pub fn crate_root() -> Result { // From the current directory we work our way up, looking for `Cargo.toml` env::current_dir() .ok() @@ -35,7 +56,7 @@ pub fn crate_root() -> Result { None }) .ok_or_else(|| { - Error::CargoError("Failed to find directory containing Cargo.toml".to_string()) + CargoError::new("Failed to find directory containing Cargo.toml".to_string()) }) } @@ -53,11 +74,11 @@ fn contains_manifest(path: &Path) -> bool { impl Metadata { /// Returns the struct filled from `cargo metadata` output /// TODO @Jon, find a different way that doesn't rely on the cargo metadata command (it's slow) - pub fn get() -> Result { + pub fn get() -> Result { let output = Command::new("cargo") .args(["metadata"]) .output() - .map_err(|_| Error::CargoError("Manifset".to_string()))?; + .map_err(|_| CargoError::new("Manifset".to_string()))?; if !output.status.success() { let mut msg = str::from_utf8(&output.stderr).unwrap().trim(); @@ -65,22 +86,22 @@ impl Metadata { msg = &msg[7..]; } - return Err(Error::CargoError(msg.to_string())); + return Err(CargoError::new(msg.to_string())); } let stdout = str::from_utf8(&output.stdout).unwrap(); if let Some(line) = stdout.lines().next() { let meta: serde_json::Value = serde_json::from_str(line) - .map_err(|_| Error::CargoError("InvalidOutput".to_string()))?; + .map_err(|_| CargoError::new("InvalidOutput".to_string()))?; let workspace_root = meta["workspace_root"] .as_str() - .ok_or_else(|| Error::CargoError("InvalidOutput".to_string()))? + .ok_or_else(|| CargoError::new("InvalidOutput".to_string()))? .into(); let target_directory = meta["target_directory"] .as_str() - .ok_or_else(|| Error::CargoError("InvalidOutput".to_string()))? + .ok_or_else(|| CargoError::new("InvalidOutput".to_string()))? .into(); return Ok(Self { @@ -89,6 +110,6 @@ impl Metadata { }); } - Err(Error::CargoError("InvalidOutput".to_string())) + Err(CargoError::new("InvalidOutput".to_string())) } } diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs new file mode 100644 index 0000000000..f7ab891240 --- /dev/null +++ b/packages/cli-config/src/config.rs @@ -0,0 +1,658 @@ +use clap::ValueEnum; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + fmt::{Display, Formatter}, + path::{Path, PathBuf}, +}; + +use crate::CargoError; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize, Debug)] +pub enum Platform { + #[clap(name = "web")] + #[serde(rename = "web")] + Web, + #[clap(name = "desktop")] + #[serde(rename = "desktop")] + Desktop, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DioxusConfig { + pub application: ApplicationConfig, + + pub web: WebConfig, + + #[serde(default)] + pub bundle: BundleConfig, + + #[serde(default = "default_plugin")] + pub plugin: toml::Value, +} + +fn default_plugin() -> toml::Value { + toml::Value::Boolean(true) +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LoadDioxusConfigError { + location: String, + error: String, +} + +impl std::fmt::Display for LoadDioxusConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{} {}", self.location, self.error) + } +} + +impl std::error::Error for LoadDioxusConfigError {} + +impl DioxusConfig { + /// Load the dioxus config from a path + pub fn load(bin: Option) -> Result, CrateConfigError> { + let crate_dir = crate::cargo::crate_root(); + + let crate_dir = match crate_dir { + Ok(dir) => { + if let Some(bin) = bin { + dir.join(bin) + } else { + dir + } + } + Err(_) => return Ok(None), + }; + let crate_dir = crate_dir.as_path(); + + let Some(dioxus_conf_file) = acquire_dioxus_toml(crate_dir) else { + return Ok(None); + }; + + let dioxus_conf_file = dioxus_conf_file.as_path(); + let cfg = toml::from_str::(&std::fs::read_to_string(dioxus_conf_file)?) + .map_err(|err| { + let error_location = dioxus_conf_file + .strip_prefix(crate_dir) + .unwrap_or(dioxus_conf_file) + .display(); + CrateConfigError::LoadDioxusConfig(LoadDioxusConfigError { + location: error_location.to_string(), + error: err.to_string(), + }) + }) + .map(Some); + match cfg { + Ok(Some(mut cfg)) => { + let name = cfg.application.name.clone(); + if cfg.bundle.identifier.is_none() { + cfg.bundle.identifier = Some(format!("io.github.{name}")); + } + if cfg.bundle.publisher.is_none() { + cfg.bundle.publisher = Some(name); + } + Ok(Some(cfg)) + } + cfg => cfg, + } + } +} + +fn acquire_dioxus_toml(dir: &Path) -> Option { + // prefer uppercase + let uppercase_conf = dir.join("Dioxus.toml"); + if uppercase_conf.is_file() { + return Some(uppercase_conf); + } + + // lowercase is fine too + let lowercase_conf = dir.join("dioxus.toml"); + if lowercase_conf.is_file() { + return Some(lowercase_conf); + } + + None +} + +impl Default for DioxusConfig { + fn default() -> Self { + let name = "name"; + Self { + application: ApplicationConfig { + name: name.into(), + default_platform: Platform::Web, + out_dir: Some(PathBuf::from("dist")), + asset_dir: Some(PathBuf::from("public")), + + tools: None, + + sub_package: None, + }, + web: WebConfig { + app: WebAppConfig { + title: Some("dioxus | ⛺".into()), + base_path: None, + }, + proxy: Some(vec![]), + watcher: WebWatcherConfig { + watch_path: Some(vec![PathBuf::from("src"), PathBuf::from("examples")]), + reload_html: Some(false), + index_on_404: Some(true), + }, + resource: WebResourceConfig { + dev: WebDevResourceConfig { + style: Some(vec![]), + script: Some(vec![]), + }, + style: Some(vec![]), + script: Some(vec![]), + }, + https: WebHttpsConfig { + enabled: None, + mkcert: None, + key_path: None, + cert_path: None, + }, + }, + bundle: BundleConfig { + identifier: Some(format!("io.github.{name}")), + publisher: Some(name.into()), + ..Default::default() + }, + plugin: toml::Value::Table(toml::map::Map::new()), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ApplicationConfig { + pub name: String, + pub default_platform: Platform, + pub out_dir: Option, + pub asset_dir: Option, + + pub tools: Option>, + + pub sub_package: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebConfig { + pub app: WebAppConfig, + pub proxy: Option>, + pub watcher: WebWatcherConfig, + pub resource: WebResourceConfig, + #[serde(default)] + pub https: WebHttpsConfig, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebAppConfig { + pub title: Option, + pub base_path: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebProxyConfig { + pub backend: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebWatcherConfig { + pub watch_path: Option>, + pub reload_html: Option, + pub index_on_404: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebResourceConfig { + pub dev: WebDevResourceConfig, + pub style: Option>, + pub script: Option>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebDevResourceConfig { + pub style: Option>, + pub script: Option>, +} + +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct WebHttpsConfig { + pub enabled: Option, + pub mkcert: Option, + pub key_path: Option, + pub cert_path: Option, +} + +#[derive(Debug, Clone)] +pub struct CrateConfig { + pub out_dir: PathBuf, + pub crate_dir: PathBuf, + pub workspace_dir: PathBuf, + pub target_dir: PathBuf, + pub asset_dir: PathBuf, + pub manifest: cargo_toml::Manifest, + pub executable: ExecutableType, + pub dioxus_config: DioxusConfig, + pub release: bool, + pub hot_reload: bool, + pub cross_origin_policy: bool, + pub verbose: bool, + pub custom_profile: Option, + pub features: Option>, +} + +#[derive(Debug)] +pub enum CrateConfigError { + Cargo(CargoError), + Io(std::io::Error), + Toml(toml::de::Error), + LoadDioxusConfig(LoadDioxusConfigError), +} + +impl From for CrateConfigError { + fn from(err: CargoError) -> Self { + Self::Cargo(err) + } +} + +impl From for CrateConfigError { + fn from(err: std::io::Error) -> Self { + Self::Io(err) + } +} + +impl From for CrateConfigError { + fn from(err: toml::de::Error) -> Self { + Self::Toml(err) + } +} + +impl From for CrateConfigError { + fn from(err: LoadDioxusConfigError) -> Self { + Self::LoadDioxusConfig(err) + } +} + +impl Display for CrateConfigError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Cargo(err) => write!(f, "{}", err), + Self::Io(err) => write!(f, "{}", err), + Self::Toml(err) => write!(f, "{}", err), + Self::LoadDioxusConfig(err) => write!(f, "{}", err), + } + } +} + +impl std::error::Error for CrateConfigError {} + +#[derive(Debug, Clone)] +pub enum ExecutableType { + Binary(String), + Lib(String), + Example(String), +} + +impl CrateConfig { + pub fn new(bin: Option) -> Result { + let dioxus_config = DioxusConfig::load(bin.clone())?.unwrap_or_default(); + + let crate_root = crate::cargo::crate_root()?; + + let crate_dir = if let Some(package) = &dioxus_config.application.sub_package { + crate_root.join(package) + } else if let Some(bin) = bin { + crate_root.join(bin) + } else { + crate_root + }; + + let meta = crate::cargo::Metadata::get()?; + let workspace_dir = meta.workspace_root; + let target_dir = meta.target_directory; + + let out_dir = match dioxus_config.application.out_dir { + Some(ref v) => crate_dir.join(v), + None => crate_dir.join("dist"), + }; + + let cargo_def = &crate_dir.join("Cargo.toml"); + + let asset_dir = match dioxus_config.application.asset_dir { + Some(ref v) => crate_dir.join(v), + None => crate_dir.join("public"), + }; + + let manifest = cargo_toml::Manifest::from_path(cargo_def).unwrap(); + + let mut output_filename = String::from("dioxus_app"); + if let Some(package) = &manifest.package.as_ref() { + output_filename = match &package.default_run { + Some(default_run_target) => default_run_target.to_owned(), + None => manifest + .bin + .iter() + .find(|b| b.name == manifest.package.as_ref().map(|pkg| pkg.name.clone())) + .or(manifest + .bin + .iter() + .find(|b| b.path == Some("src/main.rs".to_owned()))) + .or(manifest.bin.first()) + .or(manifest.lib.as_ref()) + .and_then(|prod| prod.name.clone()) + .unwrap_or(String::from("dioxus_app")), + }; + } + + let executable = ExecutableType::Binary(output_filename); + + let release = false; + let hot_reload = false; + let verbose = false; + let custom_profile = None; + let features = None; + + Ok(Self { + out_dir, + crate_dir, + workspace_dir, + target_dir, + asset_dir, + manifest, + executable, + release, + dioxus_config, + hot_reload, + cross_origin_policy: false, + custom_profile, + features, + verbose, + }) + } + + pub fn as_example(&mut self, example_name: String) -> &mut Self { + self.executable = ExecutableType::Example(example_name); + self + } + + pub fn with_release(&mut self, release: bool) -> &mut Self { + self.release = release; + self + } + + pub fn with_hot_reload(&mut self, hot_reload: bool) -> &mut Self { + self.hot_reload = hot_reload; + self + } + + pub fn with_cross_origin_policy(&mut self, cross_origin_policy: bool) -> &mut Self { + self.cross_origin_policy = cross_origin_policy; + self + } + + pub fn with_verbose(&mut self, verbose: bool) -> &mut Self { + self.verbose = verbose; + self + } + + pub fn set_profile(&mut self, profile: String) -> &mut Self { + self.custom_profile = Some(profile); + self + } + + pub fn set_features(&mut self, features: Vec) -> &mut Self { + self.features = Some(features); + self + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct BundleConfig { + pub identifier: Option, + pub publisher: Option, + pub icon: Option>, + pub resources: Option>, + pub copyright: Option, + pub category: Option, + pub short_description: Option, + pub long_description: Option, + pub external_bin: Option>, + pub deb: Option, + pub macos: Option, + pub windows: Option, +} + +impl From for tauri_bundler::BundleSettings { + fn from(val: BundleConfig) -> Self { + tauri_bundler::BundleSettings { + identifier: val.identifier, + publisher: val.publisher, + icon: val.icon, + resources: val.resources, + copyright: val.copyright, + category: val.category.and_then(|c| c.parse().ok()), + short_description: val.short_description, + long_description: val.long_description, + external_bin: val.external_bin, + deb: val.deb.map(Into::into).unwrap_or_default(), + macos: val.macos.map(Into::into).unwrap_or_default(), + windows: val.windows.map(Into::into).unwrap_or_default(), + ..Default::default() + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct DebianSettings { + pub depends: Option>, + pub files: HashMap, + pub nsis: Option, +} + +impl From for tauri_bundler::DebianSettings { + fn from(val: DebianSettings) -> Self { + tauri_bundler::DebianSettings { + depends: val.depends, + files: val.files, + desktop_template: None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct WixSettings { + pub language: Vec<(String, Option)>, + pub template: Option, + pub fragment_paths: Vec, + pub component_group_refs: Vec, + pub component_refs: Vec, + pub feature_group_refs: Vec, + pub feature_refs: Vec, + pub merge_refs: Vec, + pub skip_webview_install: bool, + pub license: Option, + pub enable_elevated_update_task: bool, + pub banner_path: Option, + pub dialog_image_path: Option, + pub fips_compliant: bool, +} + +impl From for tauri_bundler::WixSettings { + fn from(val: WixSettings) -> Self { + tauri_bundler::WixSettings { + language: tauri_bundler::bundle::WixLanguage({ + let mut languages: Vec<_> = val + .language + .iter() + .map(|l| { + ( + l.0.clone(), + tauri_bundler::bundle::WixLanguageConfig { + locale_path: l.1.clone(), + }, + ) + }) + .collect(); + if languages.is_empty() { + languages.push(("en-US".into(), Default::default())); + } + languages + }), + template: val.template, + fragment_paths: val.fragment_paths, + component_group_refs: val.component_group_refs, + component_refs: val.component_refs, + feature_group_refs: val.feature_group_refs, + feature_refs: val.feature_refs, + merge_refs: val.merge_refs, + skip_webview_install: val.skip_webview_install, + license: val.license, + enable_elevated_update_task: val.enable_elevated_update_task, + banner_path: val.banner_path, + dialog_image_path: val.dialog_image_path, + fips_compliant: val.fips_compliant, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct MacOsSettings { + pub frameworks: Option>, + pub minimum_system_version: Option, + pub license: Option, + pub exception_domain: Option, + pub signing_identity: Option, + pub provider_short_name: Option, + pub entitlements: Option, + pub info_plist_path: Option, +} + +impl From for tauri_bundler::MacOsSettings { + fn from(val: MacOsSettings) -> Self { + tauri_bundler::MacOsSettings { + frameworks: val.frameworks, + minimum_system_version: val.minimum_system_version, + license: val.license, + exception_domain: val.exception_domain, + signing_identity: val.signing_identity, + provider_short_name: val.provider_short_name, + entitlements: val.entitlements, + info_plist_path: val.info_plist_path, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WindowsSettings { + pub digest_algorithm: Option, + pub certificate_thumbprint: Option, + pub timestamp_url: Option, + pub tsp: bool, + pub wix: Option, + pub icon_path: Option, + pub webview_install_mode: WebviewInstallMode, + pub webview_fixed_runtime_path: Option, + pub allow_downgrades: bool, + pub nsis: Option, +} + +impl From for tauri_bundler::WindowsSettings { + fn from(val: WindowsSettings) -> Self { + tauri_bundler::WindowsSettings { + digest_algorithm: val.digest_algorithm, + certificate_thumbprint: val.certificate_thumbprint, + timestamp_url: val.timestamp_url, + tsp: val.tsp, + wix: val.wix.map(Into::into), + icon_path: val.icon_path.unwrap_or("icons/icon.ico".into()), + webview_install_mode: val.webview_install_mode.into(), + webview_fixed_runtime_path: val.webview_fixed_runtime_path, + allow_downgrades: val.allow_downgrades, + nsis: val.nsis.map(Into::into), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NsisSettings { + pub template: Option, + pub license: Option, + pub header_image: Option, + pub sidebar_image: Option, + pub installer_icon: Option, + pub install_mode: NSISInstallerMode, + pub languages: Option>, + pub custom_language_files: Option>, + pub display_language_selector: bool, +} + +impl From for tauri_bundler::NsisSettings { + fn from(val: NsisSettings) -> Self { + tauri_bundler::NsisSettings { + license: val.license, + header_image: val.header_image, + sidebar_image: val.sidebar_image, + installer_icon: val.installer_icon, + install_mode: val.install_mode.into(), + languages: val.languages, + display_language_selector: val.display_language_selector, + custom_language_files: None, + template: None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum NSISInstallerMode { + CurrentUser, + PerMachine, + Both, +} + +impl From for tauri_utils::config::NSISInstallerMode { + fn from(val: NSISInstallerMode) -> Self { + match val { + NSISInstallerMode::CurrentUser => tauri_utils::config::NSISInstallerMode::CurrentUser, + NSISInstallerMode::PerMachine => tauri_utils::config::NSISInstallerMode::PerMachine, + NSISInstallerMode::Both => tauri_utils::config::NSISInstallerMode::Both, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum WebviewInstallMode { + Skip, + DownloadBootstrapper { silent: bool }, + EmbedBootstrapper { silent: bool }, + OfflineInstaller { silent: bool }, + FixedRuntime { path: PathBuf }, +} + +impl WebviewInstallMode { + fn into(self) -> tauri_utils::config::WebviewInstallMode { + match self { + Self::Skip => tauri_utils::config::WebviewInstallMode::Skip, + Self::DownloadBootstrapper { silent } => { + tauri_utils::config::WebviewInstallMode::DownloadBootstrapper { silent } + } + Self::EmbedBootstrapper { silent } => { + tauri_utils::config::WebviewInstallMode::EmbedBootstrapper { silent } + } + Self::OfflineInstaller { silent } => { + tauri_utils::config::WebviewInstallMode::OfflineInstaller { silent } + } + Self::FixedRuntime { path } => { + tauri_utils::config::WebviewInstallMode::FixedRuntime { path } + } + } + } +} + +impl Default for WebviewInstallMode { + fn default() -> Self { + Self::OfflineInstaller { silent: false } + } +} diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs new file mode 100644 index 0000000000..78531cf624 --- /dev/null +++ b/packages/cli-config/src/lib.rs @@ -0,0 +1,9 @@ +#![doc = include_str!("../README.md")] +#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] +#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] + +mod config; +pub use config::*; + +mod cargo; +pub use cargo::*; diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index adb0239f2d..4eb9db09f9 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -14,6 +14,7 @@ clap = { version = "4.2", features = ["derive"] } thiserror = { workspace = true } wasm-bindgen-cli-support = "0.2" colored = "2.0.0" +dioxus-cli-config = { workspace = true } # features log = "0.4.14" diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index c85cdc4842..c385145133 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -5,6 +5,7 @@ use crate::{ DioxusConfig, }; use cargo_metadata::{diagnostic::Diagnostic, Message}; +use dioxus_cli_config::crate_root; use indicatif::{ProgressBar, ProgressStyle}; use serde::Serialize; use std::{ @@ -429,7 +430,7 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result> { } pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { - let crate_root = crate::cargo::crate_root().unwrap(); + let crate_root = crate_root().unwrap(); let custom_html_file = crate_root.join("index.html"); let mut html = if custom_html_file.is_file() { let mut buf = String::new(); diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 7fe29f8ce9..7ecc286baf 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -1,6 +1,6 @@ -use crate::cfg::Platform; #[cfg(feature = "plugin")] use crate::plugin::PluginManager; +use dioxus_cli_config::Platform; use super::*; diff --git a/packages/cli/src/cli/cfg.rs b/packages/cli/src/cli/cfg.rs index 2a441a1c85..53c64b6e2e 100644 --- a/packages/cli/src/cli/cfg.rs +++ b/packages/cli/src/cli/cfg.rs @@ -1,5 +1,4 @@ -use clap::ValueEnum; -use serde::Serialize; +use dioxus_cli_config::Platform; use super::*; @@ -91,16 +90,6 @@ pub struct ConfigOptsServe { pub features: Option>, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize, Debug)] -pub enum Platform { - #[clap(name = "web")] - #[serde(rename = "web")] - Web, - #[clap(name = "desktop")] - #[serde(rename = "desktop")] - Desktop, -} - /// Config options for the bundling system. #[derive(Clone, Debug, Default, Deserialize, Parser)] pub struct ConfigOptsBundle { diff --git a/packages/cli/src/cli/config.rs b/packages/cli/src/cli/config.rs index 45fcc2f23a..ab29f95b20 100644 --- a/packages/cli/src/cli/config.rs +++ b/packages/cli/src/cli/config.rs @@ -1,3 +1,5 @@ +use dioxus_cli_config::crate_root; + use super::*; /// Dioxus config file controls @@ -26,7 +28,7 @@ pub enum Config { impl Config { pub fn config(self) -> Result<()> { - let crate_root = crate::cargo::crate_root()?; + let crate_root = crate_root()?; match self { Config::Init { name, diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index 433d611b73..af22a17ca9 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -1,3 +1,5 @@ +use dioxus_cli_config::Platform; + use super::*; use std::{fs::create_dir_all, io::Write, path::PathBuf}; @@ -40,7 +42,7 @@ impl Serve { .unwrap_or(crate_config.dioxus_config.application.default_platform); match platform { - cfg::Platform::Web => { + Platform::Web => { // generate dev-index page Serve::regen_dev_page(&crate_config)?; @@ -48,7 +50,7 @@ impl Serve { server::web::startup(self.serve.port, crate_config.clone(), self.serve.open) .await?; } - cfg::Platform::Desktop => { + Platform::Desktop => { server::desktop::startup(crate_config.clone()).await?; } } diff --git a/packages/cli/src/config.rs b/packages/cli/src/config.rs index 3abf47f0c0..842d3bad6f 100644 --- a/packages/cli/src/config.rs +++ b/packages/cli/src/config.rs @@ -1,4 +1,5 @@ -use crate::{cfg::Platform, error::Result}; +use crate::error::Result; +use dioxus_cli_config::{crate_root, Metadata, Platform}; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, @@ -24,7 +25,7 @@ fn default_plugin() -> toml::Value { impl DioxusConfig { pub fn load(bin: Option) -> crate::error::Result> { - let crate_dir = crate::cargo::crate_root(); + let crate_dir = crate_root(); let crate_dir = match crate_dir { Ok(dir) => { @@ -224,7 +225,7 @@ impl CrateConfig { pub fn new(bin: Option) -> Result { let dioxus_config = DioxusConfig::load(bin.clone())?.unwrap_or_default(); - let crate_root = crate::cargo::crate_root()?; + let crate_root = crate_root()?; let crate_dir = if let Some(package) = &dioxus_config.application.sub_package { crate_root.join(package) @@ -234,7 +235,7 @@ impl CrateConfig { crate_root }; - let meta = crate::cargo::Metadata::get()?; + let meta = Metadata::get()?; let workspace_dir = meta.workspace_root; let target_dir = meta.target_directory; diff --git a/packages/cli/src/error.rs b/packages/cli/src/error.rs index 84b9d4b718..e8d6c91e4b 100644 --- a/packages/cli/src/error.rs +++ b/packages/cli/src/error.rs @@ -69,6 +69,20 @@ impl From for Error { } } +impl From for Error { + fn from(e: dioxus_cli_config::LoadDioxusConfigError) -> Self { + Self::RuntimeError(e.to_string()) + } +} + +impl From for Error { + fn from(e: dioxus_cli_config::CargoError) -> Self { + Self::CargoError(e.to_string()) + } +} + + + #[macro_export] macro_rules! custom_error { ($msg:literal $(,)?) => { diff --git a/packages/cli/src/lib.rs b/packages/cli/src/lib.rs index b27cf55a95..9a87a2dfa2 100644 --- a/packages/cli/src/lib.rs +++ b/packages/cli/src/lib.rs @@ -10,9 +10,6 @@ pub mod tools; pub use builder::*; -pub mod cargo; -pub use cargo::*; - pub mod cli; pub use cli::*; diff --git a/packages/cli/src/server/output.rs b/packages/cli/src/server/output.rs index 71323dd296..a221e2f9b8 100644 --- a/packages/cli/src/server/output.rs +++ b/packages/cli/src/server/output.rs @@ -1,6 +1,7 @@ use crate::server::Diagnostic; use crate::CrateConfig; use colored::Colorize; +use dioxus_cli_config::crate_root; use std::path::PathBuf; use std::process::Command; @@ -40,7 +41,7 @@ pub fn print_console_info( profile = config.custom_profile.as_ref().unwrap().to_string(); } let hot_reload = if config.hot_reload { "RSX" } else { "Normal" }; - let crate_root = crate::cargo::crate_root().unwrap(); + let crate_root = crate_root().unwrap(); let custom_html_file = if crate_root.join("index.html").is_file() { "Custom [index.html]" } else { From 1b7017f67bcc491533ce3af71650b3236dc0c35b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Nov 2023 08:36:14 -0600 Subject: [PATCH 05/17] fix formatting --- packages/cli-config/Cargo.toml | 4 ---- packages/cli/src/error.rs | 2 -- 2 files changed, 6 deletions(-) diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml index d89d411fd9..7c21f8025f 100644 --- a/packages/cli-config/Cargo.toml +++ b/packages/cli-config/Cargo.toml @@ -88,10 +88,6 @@ interprocess-docfix = { version = "1.2.2" } default = [] plugin = ["mlua"] -[[bin]] -path = "src/main.rs" -name = "dx" - [dev-dependencies] tempfile = "3.3" diff --git a/packages/cli/src/error.rs b/packages/cli/src/error.rs index e8d6c91e4b..0088492e87 100644 --- a/packages/cli/src/error.rs +++ b/packages/cli/src/error.rs @@ -81,8 +81,6 @@ impl From for Error { } } - - #[macro_export] macro_rules! custom_error { ($msg:literal $(,)?) => { From 06be18a5913f208aac45800655f90a07457f215c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Nov 2023 15:34:06 -0600 Subject: [PATCH 06/17] export lazy current config --- packages/cli-config/Cargo.toml | 81 +--- packages/cli-config/src/bundle.rs | 258 ++++++++++ packages/cli-config/src/config.rs | 458 +++++------------- packages/cli-config/src/lib.rs | 46 +- packages/cli/Cargo.toml | 2 +- packages/cli/src/builder.rs | 23 +- packages/cli/src/cli/autoformat.rs | 2 +- packages/cli/src/cli/build.rs | 2 +- packages/cli/src/cli/bundle.rs | 9 +- packages/cli/src/cli/check.rs | 2 +- packages/cli/src/cli/clean.rs | 2 +- packages/cli/src/cli/config.rs | 5 +- packages/cli/src/cli/mod.rs | 3 +- packages/cli/src/cli/serve.rs | 2 +- packages/cli/src/config.rs | 628 ------------------------- packages/cli/src/error.rs | 6 + packages/cli/src/lib.rs | 3 - packages/cli/src/server/desktop/mod.rs | 10 +- packages/cli/src/server/mod.rs | 3 +- packages/cli/src/server/output.rs | 2 +- packages/cli/src/server/web/mod.rs | 4 +- packages/cli/src/server/web/proxy.rs | 3 +- 22 files changed, 486 insertions(+), 1068 deletions(-) create mode 100644 packages/cli-config/src/bundle.rs delete mode 100644 packages/cli/src/config.rs diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml index 7c21f8025f..2ef7ce8e63 100644 --- a/packages/cli-config/Cargo.toml +++ b/packages/cli-config/Cargo.toml @@ -9,90 +9,17 @@ license = "MIT OR Apache-2.0" keywords = ["react", "gui", "cli", "dioxus", "wasm"] [dependencies] -# cli core clap = { version = "4.2", features = ["derive"] } -thiserror = { workspace = true } -wasm-bindgen-cli-support = "0.2" -colored = "2.0.0" - -# features -log = "0.4.14" -fern = { version = "0.6.0", features = ["colored"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" toml = "0.5.8" -fs_extra = "1.2.0" cargo_toml = "0.16.0" -futures = "0.3.21" -notify = { version = "5.0.0-pre.16", features = ["serde"] } -html_parser = { workspace = true } -cargo_metadata = "0.15.0" -tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] } -atty = "0.2.14" -chrono = "0.4.19" -anyhow = "1.0.53" -hyper = "0.14.17" -hyper-rustls = "0.23.2" -indicatif = "0.17.5" -subprocess = "0.2.9" - -axum = { version = "0.5.1", features = ["ws", "headers"] } -axum-server = { version = "0.5.1", features = ["tls-rustls"] } -tower-http = { version = "0.2.2", features = ["full"] } -headers = "0.3.7" - -walkdir = "2" - -# tools download -dirs = "4.0.0" -reqwest = { version = "0.11", features = [ - "rustls-tls", - "stream", - "trust-dns", - "blocking", -] } -flate2 = "1.0.22" -tar = "0.4.38" -zip = "0.6.2" -tower = "0.4.12" -syn = { version = "2.0", features = ["full", "extra-traits"] } -lazy_static = "1.4.0" - -# plugin packages -mlua = { version = "0.8.1", features = [ - "lua54", - "vendored", - "async", - "send", - "macros", -], optional = true } -ctrlc = "3.2.3" -open = "4.1.0" -cargo-generate = "0.18" -toml_edit = "0.19.11" # bundling -tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"] } -tauri-utils = "=1.4.*" - -dioxus-autofmt = { workspace = true } -dioxus-check = { workspace = true } -rsx-rosetta = { workspace = true } -dioxus-rsx = { workspace = true } -dioxus-html = { workspace = true, features = ["hot-reload-context"] } -dioxus-core = { workspace = true, features = ["serialize"] } -dioxus-hot-reload = { workspace = true } -interprocess-docfix = { version = "1.2.2" } +tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"], optional = true } +tauri-utils = { version = "=1.4.*", optional = true } +once_cell = "1.18.0" [features] default = [] -plugin = ["mlua"] - -[dev-dependencies] -tempfile = "3.3" - -[package.metadata.binstall] -pkg-url = "{ repo }/releases/download/v{ version }/dx-{ target }{ archive-suffix }" - -[package.metadata.binstall.overrides.x86_64-pc-windows-msvc] -pkg-fmt = "zip" +cli = ["tauri-bundler", "tauri-utils"] diff --git a/packages/cli-config/src/bundle.rs b/packages/cli-config/src/bundle.rs new file mode 100644 index 0000000000..cdae4539b1 --- /dev/null +++ b/packages/cli-config/src/bundle.rs @@ -0,0 +1,258 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::path::PathBuf; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct BundleConfig { + pub identifier: Option, + pub publisher: Option, + pub icon: Option>, + pub resources: Option>, + pub copyright: Option, + pub category: Option, + pub short_description: Option, + pub long_description: Option, + pub external_bin: Option>, + pub deb: Option, + pub macos: Option, + pub windows: Option, +} + +#[cfg(feature = "cli")] +impl From for tauri_bundler::BundleSettings { + fn from(val: BundleConfig) -> Self { + tauri_bundler::BundleSettings { + identifier: val.identifier, + publisher: val.publisher, + icon: val.icon, + resources: val.resources, + copyright: val.copyright, + category: val.category.and_then(|c| c.parse().ok()), + short_description: val.short_description, + long_description: val.long_description, + external_bin: val.external_bin, + deb: val.deb.map(Into::into).unwrap_or_default(), + macos: val.macos.map(Into::into).unwrap_or_default(), + windows: val.windows.map(Into::into).unwrap_or_default(), + ..Default::default() + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct DebianSettings { + pub depends: Option>, + pub files: HashMap, + pub nsis: Option, +} + +#[cfg(feature = "cli")] +impl From for tauri_bundler::DebianSettings { + fn from(val: DebianSettings) -> Self { + tauri_bundler::DebianSettings { + depends: val.depends, + files: val.files, + desktop_template: None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct WixSettings { + pub language: Vec<(String, Option)>, + pub template: Option, + pub fragment_paths: Vec, + pub component_group_refs: Vec, + pub component_refs: Vec, + pub feature_group_refs: Vec, + pub feature_refs: Vec, + pub merge_refs: Vec, + pub skip_webview_install: bool, + pub license: Option, + pub enable_elevated_update_task: bool, + pub banner_path: Option, + pub dialog_image_path: Option, + pub fips_compliant: bool, +} + +#[cfg(feature = "cli")] +impl From for tauri_bundler::WixSettings { + fn from(val: WixSettings) -> Self { + tauri_bundler::WixSettings { + language: tauri_bundler::bundle::WixLanguage({ + let mut languages: Vec<_> = val + .language + .iter() + .map(|l| { + ( + l.0.clone(), + tauri_bundler::bundle::WixLanguageConfig { + locale_path: l.1.clone(), + }, + ) + }) + .collect(); + if languages.is_empty() { + languages.push(("en-US".into(), Default::default())); + } + languages + }), + template: val.template, + fragment_paths: val.fragment_paths, + component_group_refs: val.component_group_refs, + component_refs: val.component_refs, + feature_group_refs: val.feature_group_refs, + feature_refs: val.feature_refs, + merge_refs: val.merge_refs, + skip_webview_install: val.skip_webview_install, + license: val.license, + enable_elevated_update_task: val.enable_elevated_update_task, + banner_path: val.banner_path, + dialog_image_path: val.dialog_image_path, + fips_compliant: val.fips_compliant, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct MacOsSettings { + pub frameworks: Option>, + pub minimum_system_version: Option, + pub license: Option, + pub exception_domain: Option, + pub signing_identity: Option, + pub provider_short_name: Option, + pub entitlements: Option, + pub info_plist_path: Option, +} + +#[cfg(feature = "cli")] +impl From for tauri_bundler::MacOsSettings { + fn from(val: MacOsSettings) -> Self { + tauri_bundler::MacOsSettings { + frameworks: val.frameworks, + minimum_system_version: val.minimum_system_version, + license: val.license, + exception_domain: val.exception_domain, + signing_identity: val.signing_identity, + provider_short_name: val.provider_short_name, + entitlements: val.entitlements, + info_plist_path: val.info_plist_path, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WindowsSettings { + pub digest_algorithm: Option, + pub certificate_thumbprint: Option, + pub timestamp_url: Option, + pub tsp: bool, + pub wix: Option, + pub icon_path: Option, + pub webview_install_mode: WebviewInstallMode, + pub webview_fixed_runtime_path: Option, + pub allow_downgrades: bool, + pub nsis: Option, +} + +#[cfg(feature = "cli")] +impl From for tauri_bundler::WindowsSettings { + fn from(val: WindowsSettings) -> Self { + tauri_bundler::WindowsSettings { + digest_algorithm: val.digest_algorithm, + certificate_thumbprint: val.certificate_thumbprint, + timestamp_url: val.timestamp_url, + tsp: val.tsp, + wix: val.wix.map(Into::into), + icon_path: val.icon_path.unwrap_or("icons/icon.ico".into()), + webview_install_mode: val.webview_install_mode.into(), + webview_fixed_runtime_path: val.webview_fixed_runtime_path, + allow_downgrades: val.allow_downgrades, + nsis: val.nsis.map(Into::into), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NsisSettings { + pub template: Option, + pub license: Option, + pub header_image: Option, + pub sidebar_image: Option, + pub installer_icon: Option, + pub install_mode: NSISInstallerMode, + pub languages: Option>, + pub custom_language_files: Option>, + pub display_language_selector: bool, +} + +#[cfg(feature = "cli")] +impl From for tauri_bundler::NsisSettings { + fn from(val: NsisSettings) -> Self { + tauri_bundler::NsisSettings { + license: val.license, + header_image: val.header_image, + sidebar_image: val.sidebar_image, + installer_icon: val.installer_icon, + install_mode: val.install_mode.into(), + languages: val.languages, + display_language_selector: val.display_language_selector, + custom_language_files: None, + template: None, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum NSISInstallerMode { + CurrentUser, + PerMachine, + Both, +} + +#[cfg(feature = "cli")] +impl From for tauri_utils::config::NSISInstallerMode { + fn from(val: NSISInstallerMode) -> Self { + match val { + NSISInstallerMode::CurrentUser => tauri_utils::config::NSISInstallerMode::CurrentUser, + NSISInstallerMode::PerMachine => tauri_utils::config::NSISInstallerMode::PerMachine, + NSISInstallerMode::Both => tauri_utils::config::NSISInstallerMode::Both, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum WebviewInstallMode { + Skip, + DownloadBootstrapper { silent: bool }, + EmbedBootstrapper { silent: bool }, + OfflineInstaller { silent: bool }, + FixedRuntime { path: PathBuf }, +} + +impl WebviewInstallMode { + fn into(self) -> tauri_utils::config::WebviewInstallMode { + match self { + Self::Skip => tauri_utils::config::WebviewInstallMode::Skip, + Self::DownloadBootstrapper { silent } => { + tauri_utils::config::WebviewInstallMode::DownloadBootstrapper { silent } + } + Self::EmbedBootstrapper { silent } => { + tauri_utils::config::WebviewInstallMode::EmbedBootstrapper { silent } + } + Self::OfflineInstaller { silent } => { + tauri_utils::config::WebviewInstallMode::OfflineInstaller { silent } + } + Self::FixedRuntime { path } => { + tauri_utils::config::WebviewInstallMode::FixedRuntime { path } + } + } + } +} + +impl Default for WebviewInstallMode { + fn default() -> Self { + Self::OfflineInstaller { silent: false } + } +} diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs index f7ab891240..fb3afb4ac8 100644 --- a/packages/cli-config/src/config.rs +++ b/packages/cli-config/src/config.rs @@ -1,13 +1,14 @@ +use crate::BundleConfig; +use crate::CargoError; +use crate::{crate_root, Metadata}; use clap::ValueEnum; +use core::fmt::{Display, Formatter}; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, - fmt::{Display, Formatter}, path::{Path, PathBuf}, }; -use crate::CargoError; - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize, Debug)] pub enum Platform { #[clap(name = "web")] @@ -49,6 +50,51 @@ impl std::fmt::Display for LoadDioxusConfigError { impl std::error::Error for LoadDioxusConfigError {} +#[derive(Debug)] +pub enum CrateConfigError { + Cargo(CargoError), + Io(std::io::Error), + Toml(toml::de::Error), + LoadDioxusConfig(LoadDioxusConfigError), +} + +impl From for CrateConfigError { + fn from(err: CargoError) -> Self { + Self::Cargo(err) + } +} + +impl From for CrateConfigError { + fn from(err: std::io::Error) -> Self { + Self::Io(err) + } +} + +impl From for CrateConfigError { + fn from(err: toml::de::Error) -> Self { + Self::Toml(err) + } +} + +impl From for CrateConfigError { + fn from(err: LoadDioxusConfigError) -> Self { + Self::LoadDioxusConfig(err) + } +} + +impl Display for CrateConfigError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Cargo(err) => write!(f, "{}", err), + Self::Io(err) => write!(f, "{}", err), + Self::Toml(err) => write!(f, "{}", err), + Self::LoadDioxusConfig(err) => write!(f, "{}", err), + } + } +} + +impl std::error::Error for CrateConfigError {} + impl DioxusConfig { /// Load the dioxus config from a path pub fn load(bin: Option) -> Result, CrateConfigError> { @@ -117,33 +163,33 @@ fn acquire_dioxus_toml(dir: &Path) -> Option { impl Default for DioxusConfig { fn default() -> Self { - let name = "name"; + let name = default_name(); Self { application: ApplicationConfig { - name: name.into(), - default_platform: Platform::Web, - out_dir: Some(PathBuf::from("dist")), - asset_dir: Some(PathBuf::from("public")), + name: name.clone(), + default_platform: default_platform(), + out_dir: out_dir_default(), + asset_dir: asset_dir_default(), - tools: None, + tools: Default::default(), sub_package: None, }, web: WebConfig { app: WebAppConfig { - title: Some("dioxus | ⛺".into()), + title: default_title(), base_path: None, }, - proxy: Some(vec![]), + proxy: vec![], watcher: WebWatcherConfig { - watch_path: Some(vec![PathBuf::from("src"), PathBuf::from("examples")]), - reload_html: Some(false), - index_on_404: Some(true), + watch_path: watch_path_default(), + reload_html: false, + index_on_404: true, }, resource: WebResourceConfig { dev: WebDevResourceConfig { - style: Some(vec![]), - script: Some(vec![]), + style: vec![], + script: vec![], }, style: Some(vec![]), script: Some(vec![]), @@ -157,7 +203,7 @@ impl Default for DioxusConfig { }, bundle: BundleConfig { identifier: Some(format!("io.github.{name}")), - publisher: Some(name.into()), + publisher: Some(name), ..Default::default() }, plugin: toml::Value::Table(toml::map::Map::new()), @@ -167,20 +213,44 @@ impl Default for DioxusConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationConfig { + #[serde(default = "default_name")] pub name: String, + #[serde(default = "default_platform")] pub default_platform: Platform, - pub out_dir: Option, - pub asset_dir: Option, + #[serde(default = "out_dir_default")] + pub out_dir: PathBuf, + #[serde(default = "asset_dir_default")] + pub asset_dir: PathBuf, - pub tools: Option>, + #[serde(default)] + pub tools: HashMap, + #[serde(default)] pub sub_package: Option, } +fn default_name() -> String { + "name".into() +} + +fn default_platform() -> Platform { + Platform::Web +} + +fn asset_dir_default() -> PathBuf { + PathBuf::from("public") +} + +fn out_dir_default() -> PathBuf { + PathBuf::from("dist") +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebConfig { + #[serde(default)] pub app: WebAppConfig, - pub proxy: Option>, + #[serde(default)] + pub proxy: Vec, pub watcher: WebWatcherConfig, pub resource: WebResourceConfig, #[serde(default)] @@ -189,10 +259,24 @@ pub struct WebConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebAppConfig { - pub title: Option, + #[serde(default = "default_title")] + pub title: String, pub base_path: Option, } +impl Default for WebAppConfig { + fn default() -> Self { + Self { + title: default_title(), + base_path: None, + } + } +} + +fn default_title() -> String { + "dioxus | ⛺".into() +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebProxyConfig { pub backend: String, @@ -200,9 +284,16 @@ pub struct WebProxyConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebWatcherConfig { - pub watch_path: Option>, - pub reload_html: Option, - pub index_on_404: Option, + #[serde(default = "watch_path_default")] + pub watch_path: Vec, + #[serde(default)] + pub reload_html: bool, + #[serde(default = "true_bool")] + pub index_on_404: bool, +} + +fn watch_path_default() -> Vec { + vec![PathBuf::from("src"), PathBuf::from("examples")] } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -214,8 +305,10 @@ pub struct WebResourceConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WebDevResourceConfig { - pub style: Option>, - pub script: Option>, + #[serde(default)] + pub style: Vec, + #[serde(default)] + pub script: Vec, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -226,7 +319,7 @@ pub struct WebHttpsConfig { pub cert_path: Option, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct CrateConfig { pub out_dir: PathBuf, pub crate_dir: PathBuf, @@ -244,52 +337,7 @@ pub struct CrateConfig { pub features: Option>, } -#[derive(Debug)] -pub enum CrateConfigError { - Cargo(CargoError), - Io(std::io::Error), - Toml(toml::de::Error), - LoadDioxusConfig(LoadDioxusConfigError), -} - -impl From for CrateConfigError { - fn from(err: CargoError) -> Self { - Self::Cargo(err) - } -} - -impl From for CrateConfigError { - fn from(err: std::io::Error) -> Self { - Self::Io(err) - } -} - -impl From for CrateConfigError { - fn from(err: toml::de::Error) -> Self { - Self::Toml(err) - } -} - -impl From for CrateConfigError { - fn from(err: LoadDioxusConfigError) -> Self { - Self::LoadDioxusConfig(err) - } -} - -impl Display for CrateConfigError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Self::Cargo(err) => write!(f, "{}", err), - Self::Io(err) => write!(f, "{}", err), - Self::Toml(err) => write!(f, "{}", err), - Self::LoadDioxusConfig(err) => write!(f, "{}", err), - } - } -} - -impl std::error::Error for CrateConfigError {} - -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum ExecutableType { Binary(String), Lib(String), @@ -300,7 +348,7 @@ impl CrateConfig { pub fn new(bin: Option) -> Result { let dioxus_config = DioxusConfig::load(bin.clone())?.unwrap_or_default(); - let crate_root = crate::cargo::crate_root()?; + let crate_root = crate_root()?; let crate_dir = if let Some(package) = &dioxus_config.application.sub_package { crate_root.join(package) @@ -310,21 +358,15 @@ impl CrateConfig { crate_root }; - let meta = crate::cargo::Metadata::get()?; + let meta = Metadata::get()?; let workspace_dir = meta.workspace_root; let target_dir = meta.target_directory; - let out_dir = match dioxus_config.application.out_dir { - Some(ref v) => crate_dir.join(v), - None => crate_dir.join("dist"), - }; + let out_dir = crate_dir.join(&dioxus_config.application.out_dir); let cargo_def = &crate_dir.join("Cargo.toml"); - let asset_dir = match dioxus_config.application.asset_dir { - Some(ref v) => crate_dir.join(v), - None => crate_dir.join("public"), - }; + let asset_dir = crate_dir.join(&dioxus_config.application.asset_dir); let manifest = cargo_toml::Manifest::from_path(cargo_def).unwrap(); @@ -409,250 +451,6 @@ impl CrateConfig { } } -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct BundleConfig { - pub identifier: Option, - pub publisher: Option, - pub icon: Option>, - pub resources: Option>, - pub copyright: Option, - pub category: Option, - pub short_description: Option, - pub long_description: Option, - pub external_bin: Option>, - pub deb: Option, - pub macos: Option, - pub windows: Option, -} - -impl From for tauri_bundler::BundleSettings { - fn from(val: BundleConfig) -> Self { - tauri_bundler::BundleSettings { - identifier: val.identifier, - publisher: val.publisher, - icon: val.icon, - resources: val.resources, - copyright: val.copyright, - category: val.category.and_then(|c| c.parse().ok()), - short_description: val.short_description, - long_description: val.long_description, - external_bin: val.external_bin, - deb: val.deb.map(Into::into).unwrap_or_default(), - macos: val.macos.map(Into::into).unwrap_or_default(), - windows: val.windows.map(Into::into).unwrap_or_default(), - ..Default::default() - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct DebianSettings { - pub depends: Option>, - pub files: HashMap, - pub nsis: Option, -} - -impl From for tauri_bundler::DebianSettings { - fn from(val: DebianSettings) -> Self { - tauri_bundler::DebianSettings { - depends: val.depends, - files: val.files, - desktop_template: None, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct WixSettings { - pub language: Vec<(String, Option)>, - pub template: Option, - pub fragment_paths: Vec, - pub component_group_refs: Vec, - pub component_refs: Vec, - pub feature_group_refs: Vec, - pub feature_refs: Vec, - pub merge_refs: Vec, - pub skip_webview_install: bool, - pub license: Option, - pub enable_elevated_update_task: bool, - pub banner_path: Option, - pub dialog_image_path: Option, - pub fips_compliant: bool, -} - -impl From for tauri_bundler::WixSettings { - fn from(val: WixSettings) -> Self { - tauri_bundler::WixSettings { - language: tauri_bundler::bundle::WixLanguage({ - let mut languages: Vec<_> = val - .language - .iter() - .map(|l| { - ( - l.0.clone(), - tauri_bundler::bundle::WixLanguageConfig { - locale_path: l.1.clone(), - }, - ) - }) - .collect(); - if languages.is_empty() { - languages.push(("en-US".into(), Default::default())); - } - languages - }), - template: val.template, - fragment_paths: val.fragment_paths, - component_group_refs: val.component_group_refs, - component_refs: val.component_refs, - feature_group_refs: val.feature_group_refs, - feature_refs: val.feature_refs, - merge_refs: val.merge_refs, - skip_webview_install: val.skip_webview_install, - license: val.license, - enable_elevated_update_task: val.enable_elevated_update_task, - banner_path: val.banner_path, - dialog_image_path: val.dialog_image_path, - fips_compliant: val.fips_compliant, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct MacOsSettings { - pub frameworks: Option>, - pub minimum_system_version: Option, - pub license: Option, - pub exception_domain: Option, - pub signing_identity: Option, - pub provider_short_name: Option, - pub entitlements: Option, - pub info_plist_path: Option, -} - -impl From for tauri_bundler::MacOsSettings { - fn from(val: MacOsSettings) -> Self { - tauri_bundler::MacOsSettings { - frameworks: val.frameworks, - minimum_system_version: val.minimum_system_version, - license: val.license, - exception_domain: val.exception_domain, - signing_identity: val.signing_identity, - provider_short_name: val.provider_short_name, - entitlements: val.entitlements, - info_plist_path: val.info_plist_path, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WindowsSettings { - pub digest_algorithm: Option, - pub certificate_thumbprint: Option, - pub timestamp_url: Option, - pub tsp: bool, - pub wix: Option, - pub icon_path: Option, - pub webview_install_mode: WebviewInstallMode, - pub webview_fixed_runtime_path: Option, - pub allow_downgrades: bool, - pub nsis: Option, -} - -impl From for tauri_bundler::WindowsSettings { - fn from(val: WindowsSettings) -> Self { - tauri_bundler::WindowsSettings { - digest_algorithm: val.digest_algorithm, - certificate_thumbprint: val.certificate_thumbprint, - timestamp_url: val.timestamp_url, - tsp: val.tsp, - wix: val.wix.map(Into::into), - icon_path: val.icon_path.unwrap_or("icons/icon.ico".into()), - webview_install_mode: val.webview_install_mode.into(), - webview_fixed_runtime_path: val.webview_fixed_runtime_path, - allow_downgrades: val.allow_downgrades, - nsis: val.nsis.map(Into::into), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct NsisSettings { - pub template: Option, - pub license: Option, - pub header_image: Option, - pub sidebar_image: Option, - pub installer_icon: Option, - pub install_mode: NSISInstallerMode, - pub languages: Option>, - pub custom_language_files: Option>, - pub display_language_selector: bool, -} - -impl From for tauri_bundler::NsisSettings { - fn from(val: NsisSettings) -> Self { - tauri_bundler::NsisSettings { - license: val.license, - header_image: val.header_image, - sidebar_image: val.sidebar_image, - installer_icon: val.installer_icon, - install_mode: val.install_mode.into(), - languages: val.languages, - display_language_selector: val.display_language_selector, - custom_language_files: None, - template: None, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum NSISInstallerMode { - CurrentUser, - PerMachine, - Both, -} - -impl From for tauri_utils::config::NSISInstallerMode { - fn from(val: NSISInstallerMode) -> Self { - match val { - NSISInstallerMode::CurrentUser => tauri_utils::config::NSISInstallerMode::CurrentUser, - NSISInstallerMode::PerMachine => tauri_utils::config::NSISInstallerMode::PerMachine, - NSISInstallerMode::Both => tauri_utils::config::NSISInstallerMode::Both, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum WebviewInstallMode { - Skip, - DownloadBootstrapper { silent: bool }, - EmbedBootstrapper { silent: bool }, - OfflineInstaller { silent: bool }, - FixedRuntime { path: PathBuf }, -} - -impl WebviewInstallMode { - fn into(self) -> tauri_utils::config::WebviewInstallMode { - match self { - Self::Skip => tauri_utils::config::WebviewInstallMode::Skip, - Self::DownloadBootstrapper { silent } => { - tauri_utils::config::WebviewInstallMode::DownloadBootstrapper { silent } - } - Self::EmbedBootstrapper { silent } => { - tauri_utils::config::WebviewInstallMode::EmbedBootstrapper { silent } - } - Self::OfflineInstaller { silent } => { - tauri_utils::config::WebviewInstallMode::OfflineInstaller { silent } - } - Self::FixedRuntime { path } => { - tauri_utils::config::WebviewInstallMode::FixedRuntime { path } - } - } - } -} - -impl Default for WebviewInstallMode { - fn default() -> Self { - Self::OfflineInstaller { silent: false } - } +fn true_bool() -> bool { + true } diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index 78531cf624..b7b5057607 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -4,6 +4,50 @@ mod config; pub use config::*; - +mod bundle; +pub use bundle::*; mod cargo; pub use cargo::*; + +#[doc(hidden)] +pub mod __private { + use crate::CrateConfig; + + pub const CONFIG_ENV: &str = "DIOXUS_CONFIG"; + + pub fn save_config(config: &CrateConfig) -> CrateConfigDropGuard { + std::env::set_var(CONFIG_ENV, serde_json::to_string(config).unwrap()); + CrateConfigDropGuard + } + + /// A guard that removes the config from the environment when dropped. + pub struct CrateConfigDropGuard; + + impl Drop for CrateConfigDropGuard { + fn drop(&mut self) { + std::env::remove_var(CONFIG_ENV); + } + } +} + +/// An error that occurs when the dioxus CLI was not used to build the application. +#[derive(Debug)] +pub struct DioxusCLINotUsed; + +impl std::fmt::Display for DioxusCLINotUsed { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("dioxus CLI was not used to build the application") + } +} + +impl std::error::Error for DioxusCLINotUsed {} + +/// The current crate's configuration. +pub static CURRENT_CONFIG: once_cell::sync::Lazy< + Result, +> = once_cell::sync::Lazy::new(|| { + std::env::var(crate::__private::CONFIG_ENV) + .ok() + .and_then(|config| serde_json::from_str(&config).ok()) + .ok_or(DioxusCLINotUsed) +}); diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 4eb9db09f9..050d9a78fe 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -14,7 +14,7 @@ clap = { version = "4.2", features = ["derive"] } thiserror = { workspace = true } wasm-bindgen-cli-support = "0.2" colored = "2.0.0" -dioxus-cli-config = { workspace = true } +dioxus-cli-config = { workspace = true, features = ["cli"] } # features log = "0.4.14" diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 4dd1de9703..1492e0868e 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -1,11 +1,12 @@ use crate::{ - config::{CrateConfig, ExecutableType}, error::{Error, Result}, tools::Tool, - DioxusConfig, }; use cargo_metadata::{diagnostic::Diagnostic, Message}; use dioxus_cli_config::crate_root; +use dioxus_cli_config::CrateConfig; +use dioxus_cli_config::DioxusConfig; +use dioxus_cli_config::ExecutableType; use indicatif::{ProgressBar, ProgressStyle}; use serde::Serialize; use std::{ @@ -89,6 +90,8 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; + let _ = dioxus_cli_config::__private::save_config(config); + let warning_messages = prettier_build(cmd)?; // [2] Establish the output directory structure @@ -276,11 +279,13 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result cmd.arg("--bin").arg(name), - crate::ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), - crate::ExecutableType::Example(name) => cmd.arg("--example").arg(name), + ExecutableType::Binary(name) => cmd.arg("--bin").arg(name), + ExecutableType::Lib(name) => cmd.arg("--lib").arg(name), + ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; + let _ = dioxus_cli_config::__private::save_config(config); + let warning_messages = prettier_build(cmd)?; let release_type = match config.release { @@ -290,11 +295,11 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result { + ExecutableType::Binary(name) | ExecutableType::Lib(name) => { file_name = name.clone(); config.target_dir.join(release_type).join(name) } - crate::ExecutableType::Example(name) => { + ExecutableType::Example(name) => { file_name = name.clone(); config .target_dir @@ -444,8 +449,8 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { let mut script_list = resources.script.unwrap_or_default(); if serve { - let mut dev_style = resouces.dev.style.clone(); - let mut dev_script = resouces.dev.script.clone(); + let mut dev_style = resources.dev.style.clone(); + let mut dev_script = resources.dev.script.clone(); style_list.append(&mut dev_style); script_list.append(&mut dev_script); } diff --git a/packages/cli/src/cli/autoformat.rs b/packages/cli/src/cli/autoformat.rs index 1d1cbcd246..e1e7267331 100644 --- a/packages/cli/src/cli/autoformat.rs +++ b/packages/cli/src/cli/autoformat.rs @@ -88,7 +88,7 @@ impl Autoformat { /// /// Doesn't do mod-descending, so it will still try to format unreachable files. TODO. async fn autoformat_project(check: bool) -> Result<()> { - let crate_config = crate::CrateConfig::new(None)?; + let crate_config = dioxus_cli_config::CrateConfig::new(None)?; let mut files_to_format = vec![]; collect_rs_files(&crate_config.crate_dir, &mut files_to_format); diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 675880111a..f4d1d24573 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -14,7 +14,7 @@ pub struct Build { impl Build { pub fn build(self, bin: Option) -> Result<()> { - let mut crate_config = crate::CrateConfig::new(bin)?; + let mut crate_config = dioxus_cli_config::CrateConfig::new(bin)?; // change the release state. crate_config.with_release(self.build.release); diff --git a/packages/cli/src/cli/bundle.rs b/packages/cli/src/cli/bundle.rs index 80b52cf2fa..8ee0c2fb15 100644 --- a/packages/cli/src/cli/bundle.rs +++ b/packages/cli/src/cli/bundle.rs @@ -1,4 +1,5 @@ use core::panic; +use dioxus_cli_config::ExecutableType; use std::{fs::create_dir_all, str::FromStr}; use tauri_bundler::{BundleSettings, PackageSettings, SettingsBuilder}; @@ -62,7 +63,7 @@ impl From for tauri_bundler::PackageType { impl Bundle { pub fn bundle(self, bin: Option) -> Result<()> { - let mut crate_config = crate::CrateConfig::new(bin)?; + let mut crate_config = dioxus_cli_config::CrateConfig::new(bin)?; // change the release state. crate_config.with_release(self.build.release); @@ -83,9 +84,9 @@ impl Bundle { let package = crate_config.manifest.package.unwrap(); let mut name: PathBuf = match &crate_config.executable { - crate::ExecutableType::Binary(name) - | crate::ExecutableType::Lib(name) - | crate::ExecutableType::Example(name) => name, + ExecutableType::Binary(name) + | ExecutableType::Lib(name) + | ExecutableType::Example(name) => name, } .into(); if cfg!(windows) { diff --git a/packages/cli/src/cli/check.rs b/packages/cli/src/cli/check.rs index a4d84addb0..0832647f2f 100644 --- a/packages/cli/src/cli/check.rs +++ b/packages/cli/src/cli/check.rs @@ -47,7 +47,7 @@ async fn check_file_and_report(path: PathBuf) -> Result<()> { /// /// Doesn't do mod-descending, so it will still try to check unreachable files. TODO. async fn check_project_and_report() -> Result<()> { - let crate_config = crate::CrateConfig::new(None)?; + let crate_config = dioxus_cli_config::CrateConfig::new(None)?; let mut files_to_check = vec![]; collect_rs_files(&crate_config.crate_dir, &mut files_to_check); diff --git a/packages/cli/src/cli/clean.rs b/packages/cli/src/cli/clean.rs index 09fb214690..cfe44e3747 100644 --- a/packages/cli/src/cli/clean.rs +++ b/packages/cli/src/cli/clean.rs @@ -7,7 +7,7 @@ pub struct Clean {} impl Clean { pub fn clean(self, bin: Option) -> Result<()> { - let crate_config = crate::CrateConfig::new(bin)?; + let crate_config = dioxus_cli_config::CrateConfig::new(bin)?; let output = Command::new("cargo") .arg("clean") diff --git a/packages/cli/src/cli/config.rs b/packages/cli/src/cli/config.rs index ab29f95b20..1a1072c2f4 100644 --- a/packages/cli/src/cli/config.rs +++ b/packages/cli/src/cli/config.rs @@ -50,7 +50,10 @@ impl Config { log::info!("🚩 Init config file completed."); } Config::FormatPrint {} => { - println!("{:#?}", crate::CrateConfig::new(None)?.dioxus_config); + println!( + "{:#?}", + dioxus_cli_config::CrateConfig::new(None)?.dioxus_config + ); } Config::CustomHtml {} => { let html_path = crate_root.join("index.html"); diff --git a/packages/cli/src/cli/mod.rs b/packages/cli/src/cli/mod.rs index 9b3be33bc8..4295bfa9bd 100644 --- a/packages/cli/src/cli/mod.rs +++ b/packages/cli/src/cli/mod.rs @@ -15,9 +15,10 @@ use crate::{ cfg::{ConfigOptsBuild, ConfigOptsServe}, custom_error, error::Result, - gen_page, server, CrateConfig, Error, + gen_page, server, Error, }; use clap::{Parser, Subcommand}; +use dioxus_cli_config::CrateConfig; use html_parser::Dom; use serde::Deserialize; use std::{ diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index 6d5c063f7e..b4d60b7696 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -13,7 +13,7 @@ pub struct Serve { impl Serve { pub async fn serve(self, bin: Option) -> Result<()> { - let mut crate_config = crate::CrateConfig::new(bin)?; + let mut crate_config = dioxus_cli_config::CrateConfig::new(bin)?; // change the relase state. crate_config.with_hot_reload(self.serve.hot_reload); diff --git a/packages/cli/src/config.rs b/packages/cli/src/config.rs deleted file mode 100644 index 14e345c7a0..0000000000 --- a/packages/cli/src/config.rs +++ /dev/null @@ -1,628 +0,0 @@ -use crate::error::Result; -use dioxus_cli_config::{crate_root, Metadata, Platform}; -use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - path::{Path, PathBuf}, -}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct DioxusConfig { - pub application: ApplicationConfig, - - pub web: WebConfig, - - #[serde(default)] - pub bundle: BundleConfig, - - #[serde(default = "default_plugin")] - pub plugin: toml::Value, -} - -fn default_plugin() -> toml::Value { - toml::Value::Boolean(true) -} - -impl DioxusConfig { - pub fn load(bin: Option) -> crate::error::Result> { - let crate_dir = crate_root(); - - let crate_dir = match crate_dir { - Ok(dir) => { - if let Some(bin) = bin { - dir.join(bin) - } else { - dir - } - } - Err(_) => return Ok(None), - }; - let crate_dir = crate_dir.as_path(); - - let Some(dioxus_conf_file) = acquire_dioxus_toml(crate_dir) else { - return Ok(None); - }; - - let dioxus_conf_file = dioxus_conf_file.as_path(); - let cfg = toml::from_str::(&std::fs::read_to_string(dioxus_conf_file)?) - .map_err(|err| { - let error_location = dioxus_conf_file - .strip_prefix(crate_dir) - .unwrap_or(dioxus_conf_file) - .display(); - crate::Error::Unique(format!("{error_location} {err}")) - }) - .map(Some); - match cfg { - Ok(Some(mut cfg)) => { - let name = cfg.application.name.clone(); - if cfg.bundle.identifier.is_none() { - cfg.bundle.identifier = Some(format!("io.github.{name}")); - } - if cfg.bundle.publisher.is_none() { - cfg.bundle.publisher = Some(name); - } - Ok(Some(cfg)) - } - cfg => cfg, - } - } -} - -fn acquire_dioxus_toml(dir: &Path) -> Option { - // prefer uppercase - let uppercase_conf = dir.join("Dioxus.toml"); - if uppercase_conf.is_file() { - return Some(uppercase_conf); - } - - // lowercase is fine too - let lowercase_conf = dir.join("dioxus.toml"); - if lowercase_conf.is_file() { - return Some(lowercase_conf); - } - - None -} - -impl Default for DioxusConfig { - fn default() -> Self { - let name = default_name(); - Self { - application: ApplicationConfig { - name: name.clone(), - default_platform: default_platform(), - out_dir: out_dir_default(), - asset_dir: asset_dir_default(), - - tools: Default::default(), - - sub_package: None, - }, - web: WebConfig { - app: WebAppConfig { - title: default_title(), - base_path: None, - }, - proxy: vec![], - watcher: WebWatcherConfig { - watch_path: watch_path_default(), - reload_html: false, - index_on_404: true, - }, - resource: WebResourceConfig { - dev: WebDevResourceConfig { - style: vec![], - script: vec![], - }, - style: Some(vec![]), - script: Some(vec![]), - }, - https: WebHttpsConfig { - enabled: None, - mkcert: None, - key_path: None, - cert_path: None, - }, - }, - bundle: BundleConfig { - identifier: Some(format!("io.github.{name}")), - publisher: Some(name), - ..Default::default() - }, - plugin: toml::Value::Table(toml::map::Map::new()), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ApplicationConfig { - #[serde(default = "default_name")] - pub name: String, - #[serde(default = "default_platform")] - pub default_platform: Platform, - #[serde(default = "out_dir_default")] - pub out_dir: PathBuf, - #[serde(default = "asset_dir_default")] - pub asset_dir: PathBuf, - - #[serde(default)] - pub tools: HashMap, - - #[serde(default)] - pub sub_package: Option, -} - -fn default_name() -> String { - "name".into() -} - -fn default_platform() -> Platform { - Platform::Web -} - -fn asset_dir_default() -> PathBuf { - PathBuf::from("public") -} - -fn out_dir_default() -> PathBuf { - PathBuf::from("dist") -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebConfig { - #[serde(default)] - pub app: WebAppConfig, - #[serde(default)] - pub proxy: Vec, - pub watcher: WebWatcherConfig, - pub resource: WebResourceConfig, - #[serde(default)] - pub https: WebHttpsConfig, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebAppConfig { - #[serde(default = "default_title")] - pub title: String, - pub base_path: Option, -} - -impl Default for WebAppConfig { - fn default() -> Self { - Self { - title: default_title(), - base_path: None, - } - } -} - -fn default_title() -> String { - "dioxus | ⛺".into() -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebProxyConfig { - pub backend: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebWatcherConfig { - #[serde(default = "watch_path_default")] - pub watch_path: Vec, - #[serde(default)] - pub reload_html: bool, - #[serde(default = "true_bool")] - pub index_on_404: bool, -} - -fn watch_path_default() -> Vec { - vec![PathBuf::from("src"), PathBuf::from("examples")] -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebResourceConfig { - pub dev: WebDevResourceConfig, - pub style: Option>, - pub script: Option>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WebDevResourceConfig { - #[serde(default)] - pub style: Vec, - #[serde(default)] - pub script: Vec, -} - -#[derive(Debug, Default, Clone, Serialize, Deserialize)] -pub struct WebHttpsConfig { - pub enabled: Option, - pub mkcert: Option, - pub key_path: Option, - pub cert_path: Option, -} - -#[derive(Debug, Clone)] -pub struct CrateConfig { - pub out_dir: PathBuf, - pub crate_dir: PathBuf, - pub workspace_dir: PathBuf, - pub target_dir: PathBuf, - pub asset_dir: PathBuf, - pub manifest: cargo_toml::Manifest, - pub executable: ExecutableType, - pub dioxus_config: DioxusConfig, - pub release: bool, - pub hot_reload: bool, - pub cross_origin_policy: bool, - pub verbose: bool, - pub custom_profile: Option, - pub features: Option>, -} - -#[derive(Debug, Clone)] -pub enum ExecutableType { - Binary(String), - Lib(String), - Example(String), -} - -impl CrateConfig { - pub fn new(bin: Option) -> Result { - let dioxus_config = DioxusConfig::load(bin.clone())?.unwrap_or_default(); - - let crate_root = crate_root()?; - - let crate_dir = if let Some(package) = &dioxus_config.application.sub_package { - crate_root.join(package) - } else if let Some(bin) = bin { - crate_root.join(bin) - } else { - crate_root - }; - - let meta = Metadata::get()?; - let workspace_dir = meta.workspace_root; - let target_dir = meta.target_directory; - - let out_dir = crate_dir.join(&dioxus_config.application.out_dir); - - let cargo_def = &crate_dir.join("Cargo.toml"); - - let asset_dir = crate_dir.join(&dioxus_config.application.asset_dir); - - let manifest = cargo_toml::Manifest::from_path(cargo_def).unwrap(); - - let mut output_filename = String::from("dioxus_app"); - if let Some(package) = &manifest.package.as_ref() { - output_filename = match &package.default_run { - Some(default_run_target) => default_run_target.to_owned(), - None => manifest - .bin - .iter() - .find(|b| b.name == manifest.package.as_ref().map(|pkg| pkg.name.clone())) - .or(manifest - .bin - .iter() - .find(|b| b.path == Some("src/main.rs".to_owned()))) - .or(manifest.bin.first()) - .or(manifest.lib.as_ref()) - .and_then(|prod| prod.name.clone()) - .unwrap_or(String::from("dioxus_app")), - }; - } - - let executable = ExecutableType::Binary(output_filename); - - let release = false; - let hot_reload = false; - let verbose = false; - let custom_profile = None; - let features = None; - - Ok(Self { - out_dir, - crate_dir, - workspace_dir, - target_dir, - asset_dir, - manifest, - executable, - release, - dioxus_config, - hot_reload, - cross_origin_policy: false, - custom_profile, - features, - verbose, - }) - } - - pub fn as_example(&mut self, example_name: String) -> &mut Self { - self.executable = ExecutableType::Example(example_name); - self - } - - pub fn with_release(&mut self, release: bool) -> &mut Self { - self.release = release; - self - } - - pub fn with_hot_reload(&mut self, hot_reload: bool) -> &mut Self { - self.hot_reload = hot_reload; - self - } - - pub fn with_cross_origin_policy(&mut self, cross_origin_policy: bool) -> &mut Self { - self.cross_origin_policy = cross_origin_policy; - self - } - - pub fn with_verbose(&mut self, verbose: bool) -> &mut Self { - self.verbose = verbose; - self - } - - pub fn set_profile(&mut self, profile: String) -> &mut Self { - self.custom_profile = Some(profile); - self - } - - pub fn set_features(&mut self, features: Vec) -> &mut Self { - self.features = Some(features); - self - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct BundleConfig { - pub identifier: Option, - pub publisher: Option, - pub icon: Option>, - pub resources: Option>, - pub copyright: Option, - pub category: Option, - pub short_description: Option, - pub long_description: Option, - pub external_bin: Option>, - pub deb: Option, - pub macos: Option, - pub windows: Option, -} - -impl From for tauri_bundler::BundleSettings { - fn from(val: BundleConfig) -> Self { - tauri_bundler::BundleSettings { - identifier: val.identifier, - publisher: val.publisher, - icon: val.icon, - resources: val.resources, - copyright: val.copyright, - category: val.category.and_then(|c| c.parse().ok()), - short_description: val.short_description, - long_description: val.long_description, - external_bin: val.external_bin, - deb: val.deb.map(Into::into).unwrap_or_default(), - macos: val.macos.map(Into::into).unwrap_or_default(), - windows: val.windows.map(Into::into).unwrap_or_default(), - ..Default::default() - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct DebianSettings { - pub depends: Option>, - pub files: HashMap, - pub nsis: Option, -} - -impl From for tauri_bundler::DebianSettings { - fn from(val: DebianSettings) -> Self { - tauri_bundler::DebianSettings { - depends: val.depends, - files: val.files, - desktop_template: None, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct WixSettings { - pub language: Vec<(String, Option)>, - pub template: Option, - pub fragment_paths: Vec, - pub component_group_refs: Vec, - pub component_refs: Vec, - pub feature_group_refs: Vec, - pub feature_refs: Vec, - pub merge_refs: Vec, - pub skip_webview_install: bool, - pub license: Option, - pub enable_elevated_update_task: bool, - pub banner_path: Option, - pub dialog_image_path: Option, - pub fips_compliant: bool, -} - -impl From for tauri_bundler::WixSettings { - fn from(val: WixSettings) -> Self { - tauri_bundler::WixSettings { - language: tauri_bundler::bundle::WixLanguage({ - let mut languages: Vec<_> = val - .language - .iter() - .map(|l| { - ( - l.0.clone(), - tauri_bundler::bundle::WixLanguageConfig { - locale_path: l.1.clone(), - }, - ) - }) - .collect(); - if languages.is_empty() { - languages.push(("en-US".into(), Default::default())); - } - languages - }), - template: val.template, - fragment_paths: val.fragment_paths, - component_group_refs: val.component_group_refs, - component_refs: val.component_refs, - feature_group_refs: val.feature_group_refs, - feature_refs: val.feature_refs, - merge_refs: val.merge_refs, - skip_webview_install: val.skip_webview_install, - license: val.license, - enable_elevated_update_task: val.enable_elevated_update_task, - banner_path: val.banner_path, - dialog_image_path: val.dialog_image_path, - fips_compliant: val.fips_compliant, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -pub struct MacOsSettings { - pub frameworks: Option>, - pub minimum_system_version: Option, - pub license: Option, - pub exception_domain: Option, - pub signing_identity: Option, - pub provider_short_name: Option, - pub entitlements: Option, - pub info_plist_path: Option, -} - -impl From for tauri_bundler::MacOsSettings { - fn from(val: MacOsSettings) -> Self { - tauri_bundler::MacOsSettings { - frameworks: val.frameworks, - minimum_system_version: val.minimum_system_version, - license: val.license, - exception_domain: val.exception_domain, - signing_identity: val.signing_identity, - provider_short_name: val.provider_short_name, - entitlements: val.entitlements, - info_plist_path: val.info_plist_path, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct WindowsSettings { - pub digest_algorithm: Option, - pub certificate_thumbprint: Option, - pub timestamp_url: Option, - pub tsp: bool, - pub wix: Option, - pub icon_path: Option, - pub webview_install_mode: WebviewInstallMode, - pub webview_fixed_runtime_path: Option, - pub allow_downgrades: bool, - pub nsis: Option, -} - -impl From for tauri_bundler::WindowsSettings { - fn from(val: WindowsSettings) -> Self { - tauri_bundler::WindowsSettings { - digest_algorithm: val.digest_algorithm, - certificate_thumbprint: val.certificate_thumbprint, - timestamp_url: val.timestamp_url, - tsp: val.tsp, - wix: val.wix.map(Into::into), - icon_path: val.icon_path.unwrap_or("icons/icon.ico".into()), - webview_install_mode: val.webview_install_mode.into(), - webview_fixed_runtime_path: val.webview_fixed_runtime_path, - allow_downgrades: val.allow_downgrades, - nsis: val.nsis.map(Into::into), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct NsisSettings { - pub template: Option, - pub license: Option, - pub header_image: Option, - pub sidebar_image: Option, - pub installer_icon: Option, - pub install_mode: NSISInstallerMode, - pub languages: Option>, - pub custom_language_files: Option>, - pub display_language_selector: bool, -} - -impl From for tauri_bundler::NsisSettings { - fn from(val: NsisSettings) -> Self { - tauri_bundler::NsisSettings { - license: val.license, - header_image: val.header_image, - sidebar_image: val.sidebar_image, - installer_icon: val.installer_icon, - install_mode: val.install_mode.into(), - languages: val.languages, - display_language_selector: val.display_language_selector, - custom_language_files: None, - template: None, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum NSISInstallerMode { - CurrentUser, - PerMachine, - Both, -} - -impl From for tauri_utils::config::NSISInstallerMode { - fn from(val: NSISInstallerMode) -> Self { - match val { - NSISInstallerMode::CurrentUser => tauri_utils::config::NSISInstallerMode::CurrentUser, - NSISInstallerMode::PerMachine => tauri_utils::config::NSISInstallerMode::PerMachine, - NSISInstallerMode::Both => tauri_utils::config::NSISInstallerMode::Both, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum WebviewInstallMode { - Skip, - DownloadBootstrapper { silent: bool }, - EmbedBootstrapper { silent: bool }, - OfflineInstaller { silent: bool }, - FixedRuntime { path: PathBuf }, -} - -impl WebviewInstallMode { - fn into(self) -> tauri_utils::config::WebviewInstallMode { - match self { - Self::Skip => tauri_utils::config::WebviewInstallMode::Skip, - Self::DownloadBootstrapper { silent } => { - tauri_utils::config::WebviewInstallMode::DownloadBootstrapper { silent } - } - Self::EmbedBootstrapper { silent } => { - tauri_utils::config::WebviewInstallMode::EmbedBootstrapper { silent } - } - Self::OfflineInstaller { silent } => { - tauri_utils::config::WebviewInstallMode::OfflineInstaller { silent } - } - Self::FixedRuntime { path } => { - tauri_utils::config::WebviewInstallMode::FixedRuntime { path } - } - } - } -} - -impl Default for WebviewInstallMode { - fn default() -> Self { - Self::OfflineInstaller { silent: false } - } -} - -fn true_bool() -> bool { - true -} diff --git a/packages/cli/src/error.rs b/packages/cli/src/error.rs index 0088492e87..a9578351bc 100644 --- a/packages/cli/src/error.rs +++ b/packages/cli/src/error.rs @@ -81,6 +81,12 @@ impl From for Error { } } +impl From for Error { + fn from(e: dioxus_cli_config::CrateConfigError) -> Self { + Self::RuntimeError(e.to_string()) + } +} + #[macro_export] macro_rules! custom_error { ($msg:literal $(,)?) => { diff --git a/packages/cli/src/lib.rs b/packages/cli/src/lib.rs index 9a87a2dfa2..63ec1fac05 100644 --- a/packages/cli/src/lib.rs +++ b/packages/cli/src/lib.rs @@ -13,9 +13,6 @@ pub use builder::*; pub mod cli; pub use cli::*; -pub mod config; -pub use config::*; - pub mod error; pub use error::*; diff --git a/packages/cli/src/server/desktop/mod.rs b/packages/cli/src/server/desktop/mod.rs index 978b97d43e..3fd9de2a2c 100644 --- a/packages/cli/src/server/desktop/mod.rs +++ b/packages/cli/src/server/desktop/mod.rs @@ -3,8 +3,10 @@ use crate::{ output::{print_console_info, PrettierOptions}, setup_file_watcher, }, - BuildResult, CrateConfig, Result, + BuildResult, Result, }; +use dioxus_cli_config::CrateConfig; +use dioxus_cli_config::ExecutableType; use dioxus_hot_reload::HotReloadMsg; use dioxus_html::HtmlCtx; @@ -215,9 +217,9 @@ pub fn start_desktop(config: &CrateConfig) -> Result<(Child, BuildResult)> { let result = crate::builder::build_desktop(config, true)?; match &config.executable { - crate::ExecutableType::Binary(name) - | crate::ExecutableType::Lib(name) - | crate::ExecutableType::Example(name) => { + ExecutableType::Binary(name) + | ExecutableType::Lib(name) + | ExecutableType::Example(name) => { let mut file = config.out_dir.join(name); if cfg!(windows) { file.set_extension("exe"); diff --git a/packages/cli/src/server/mod.rs b/packages/cli/src/server/mod.rs index 7b60c81785..a386362c0f 100644 --- a/packages/cli/src/server/mod.rs +++ b/packages/cli/src/server/mod.rs @@ -1,4 +1,5 @@ -use crate::{BuildResult, CrateConfig, Result}; +use crate::{BuildResult, Result}; +use dioxus_cli_config::CrateConfig; use cargo_metadata::diagnostic::Diagnostic; use dioxus_core::Template; diff --git a/packages/cli/src/server/output.rs b/packages/cli/src/server/output.rs index 151e290993..64bd305ddb 100644 --- a/packages/cli/src/server/output.rs +++ b/packages/cli/src/server/output.rs @@ -1,7 +1,7 @@ use crate::server::Diagnostic; -use crate::CrateConfig; use colored::Colorize; use dioxus_cli_config::crate_root; +use dioxus_cli_config::CrateConfig; use std::path::PathBuf; use std::process::Command; diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index f192f0f528..1c5bade15a 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -5,7 +5,7 @@ use crate::{ output::{print_console_info, PrettierOptions, WebServerInfo}, setup_file_watcher, HotReloadState, }, - BuildResult, CrateConfig, Result, WebHttpsConfig, + BuildResult, Result, }; use axum::{ body::{Full, HttpBody}, @@ -19,6 +19,8 @@ use axum::{ Router, }; use axum_server::tls_rustls::RustlsConfig; +use dioxus_cli_config::CrateConfig; +use dioxus_cli_config::WebHttpsConfig; use dioxus_html::HtmlCtx; use dioxus_rsx::hot_reload::*; diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index e35635b6bc..4242a55eb0 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -1,4 +1,5 @@ -use crate::{Result, WebProxyConfig}; +use crate::Result; +use dioxus_cli_config::WebProxyConfig; use anyhow::Context; use axum::{http::StatusCode, routing::any, Router}; From 1ed66a54ccb1bea750ee8dd6cdb91bb45b5d33cd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Nov 2023 15:50:04 -0600 Subject: [PATCH 07/17] fix cli configuration environment variable --- packages/cli-config/Cargo.toml | 1 + packages/cli-config/src/assets/dioxus.toml | 74 ---------------------- packages/cli-config/src/bundle.rs | 1 + packages/cli-config/src/lib.rs | 11 +++- packages/cli/src/builder.rs | 6 +- packages/cli/src/main.rs | 1 + 6 files changed, 13 insertions(+), 81 deletions(-) delete mode 100644 packages/cli-config/src/assets/dioxus.toml diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml index 2ef7ce8e63..376dd32406 100644 --- a/packages/cli-config/Cargo.toml +++ b/packages/cli-config/Cargo.toml @@ -19,6 +19,7 @@ cargo_toml = "0.16.0" tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"], optional = true } tauri-utils = { version = "=1.4.*", optional = true } once_cell = "1.18.0" +tracing.workspace = true [features] default = [] diff --git a/packages/cli-config/src/assets/dioxus.toml b/packages/cli-config/src/assets/dioxus.toml deleted file mode 100644 index 892a6cdf83..0000000000 --- a/packages/cli-config/src/assets/dioxus.toml +++ /dev/null @@ -1,74 +0,0 @@ -[application] - -# dioxus project name -name = "{{project-name}}" - -# default platfrom -# you can also use `dx serve/build --platform XXX` to use other platform -# value: web | desktop -default_platform = "{{default-platform}}" - -# Web `build` & `serve` dist path -out_dir = "dist" - -# resource (static) file folder -asset_dir = "public" - -[web.app] - -# HTML title tag content -title = "Dioxus | An elegant GUI library for Rust" - -[web.watcher] - -index_on_404 = true - -watch_path = ["src", "examples"] - -# include `assets` in web platform -[web.resource] - -# CSS style file -style = [] - -# Javascript code file -script = [] - -[web.resource.dev] - -# Javascript code file -# serve: [dev-server] only -script = [] - -[application.plugins] - -available = true - -required = [] - -[bundler] -# Bundle identifier -identifier = "io.github.{{project-name}}" - -# Bundle publisher -publisher = "{{project-name}}" - -# Bundle icon -icon = ["icons/icon.png"] - -# Bundle resources -resources = ["public/*"] - -# Bundle copyright -copyright = "" - -# Bundle category -category = "Utility" - -# Bundle short description -short_description = "An amazing dioxus application." - -# Bundle long description -long_description = """ -An amazing dioxus application. -""" \ No newline at end of file diff --git a/packages/cli-config/src/bundle.rs b/packages/cli-config/src/bundle.rs index cdae4539b1..4f44036d71 100644 --- a/packages/cli-config/src/bundle.rs +++ b/packages/cli-config/src/bundle.rs @@ -231,6 +231,7 @@ pub enum WebviewInstallMode { FixedRuntime { path: PathBuf }, } +#[cfg(feature = "cli")] impl WebviewInstallMode { fn into(self) -> tauri_utils::config::WebviewInstallMode { match self { diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index b7b5057607..776d1d10c2 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -46,8 +46,13 @@ impl std::error::Error for DioxusCLINotUsed {} pub static CURRENT_CONFIG: once_cell::sync::Lazy< Result, > = once_cell::sync::Lazy::new(|| { - std::env::var(crate::__private::CONFIG_ENV) - .ok() + CURRENT_CONFIG_JSON .and_then(|config| serde_json::from_str(&config).ok()) - .ok_or(DioxusCLINotUsed) + .ok_or_else(|| { + tracing::error!("A library is trying to access the crate's configuration, but the dioxus CLI was not used to build the application."); + DioxusCLINotUsed + }) }); + +/// The current crate's configuration. +pub const CURRENT_CONFIG_JSON: Option<&str> = std::option_env!("DIOXUS_CONFIG"); diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 1492e0868e..a2ee2c73ff 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -47,6 +47,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { let ignore_files = build_assets(config)?; let t_start = std::time::Instant::now(); + let _guard = dioxus_cli_config::__private::save_config(config); // [1] Build the .wasm module log::info!("🚅 Running build command..."); @@ -90,8 +91,6 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result { ExecutableType::Example(name) => cmd.arg("--example").arg(name), }; - let _ = dioxus_cli_config::__private::save_config(config); - let warning_messages = prettier_build(cmd)?; // [2] Establish the output directory structure @@ -254,6 +253,7 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result Result cmd.arg("--example").arg(name), }; - let _ = dioxus_cli_config::__private::save_config(config); - let warning_messages = prettier_build(cmd)?; let release_type = match config.release { diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index fe860a0e6a..51b884a9ac 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -1,3 +1,4 @@ +use dioxus_cli_config::DioxusConfig; use std::path::PathBuf; use anyhow::anyhow; From 15984b78dbac9c6935b564b2579bfcc1b2fd99b4 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Nov 2023 15:53:11 -0600 Subject: [PATCH 08/17] use the name in the dioxus.toml in desktop if no name was set in the desktop config --- packages/desktop/Cargo.toml | 1 + packages/desktop/src/cfg.rs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index dcb9941204..24c938c01d 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -14,6 +14,7 @@ dioxus-core = { workspace = true, features = ["serialize"] } dioxus-html = { workspace = true, features = ["serialize", "native-bind"] } dioxus-interpreter-js = { workspace = true } dioxus-hot-reload = { workspace = true, optional = true } +dioxus-cli-config = { workspace = true } serde = "1.0.136" serde_json = "1.0.79" diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index 07281e3645..a2dad21c5c 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -49,7 +49,12 @@ impl Config { /// Initializes a new `WindowBuilder` with default values. #[inline] pub fn new() -> Self { - let window = WindowBuilder::new().with_title("Dioxus app"); + let window = WindowBuilder::new().with_title( + dioxus_cli_config::CURRENT_CONFIG + .as_ref() + .map(|c| c.dioxus_config.application.name.clone()) + .unwrap_or("Dioxus App".to_string()), + ); Self { // event_handler: None, From 109e10e406e6bf1c90f4c635e79126a43d9e573f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Nov 2023 16:49:06 -0600 Subject: [PATCH 09/17] use a default base path for the web router from the config --- packages/router/Cargo.toml | 1 + packages/router/src/history/web.rs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/router/Cargo.toml b/packages/router/Cargo.toml index da9d3fe854..f07c3a724a 100644 --- a/packages/router/Cargo.toml +++ b/packages/router/Cargo.toml @@ -30,6 +30,7 @@ gloo-utils = { version = "0.1.6", optional = true } dioxus-liveview = { workspace = true, optional = true } dioxus-ssr = { workspace = true, optional = true } tokio = { workspace = true, features = ["full"], optional = true } +dioxus-cli-config.workspace = true [features] default = ["web"] diff --git a/packages/router/src/history/web.rs b/packages/router/src/history/web.rs index 789eed76e2..5b6ae0528e 100644 --- a/packages/router/src/history/web.rs +++ b/packages/router/src/history/web.rs @@ -13,6 +13,17 @@ use super::{ HistoryProvider, }; +#[allow(dead_code)] +fn base_path() -> Option<&'static str> { + dioxus_cli_config::CURRENT_CONFIG.as_ref().ok().and_then(|c| { + c.dioxus_config + .web + .app + .base_path + .as_deref() + }) + } + #[cfg(not(feature = "serde"))] #[allow(clippy::extra_unused_type_parameters)] fn update_scroll(window: &Window, history: &History) { @@ -165,7 +176,7 @@ impl WebHistory { history, listener_navigation: None, listener_animation_frame: Default::default(), - prefix, + prefix: prefix.or_else(||base_path().map(|s| s.to_string())), window, phantom: Default::default(), } @@ -198,6 +209,16 @@ where let location = self.window.location(); let path = location.pathname().unwrap_or_else(|_| "/".into()) + &location.search().unwrap_or("".into()); + let path = match self.prefix { + None => path, + Some(ref prefix) => { + if path.starts_with(prefix) { + path[prefix.len()..].to_string() + } else { + path + } + } + }; R::from_str(&path).unwrap_or_else(|err| panic!("{}", err)) } From cd48b3b7f942a47d1e2126a3c5c5640325fd4552 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 15 Nov 2023 08:23:12 -0600 Subject: [PATCH 10/17] allow base_path in the CLI --- packages/cli/Cargo.toml | 2 +- packages/cli/src/cli/serve.rs | 3 --- packages/cli/src/server/web/mod.rs | 15 +++++++++++++++ packages/router/src/history/web.rs | 21 ++++++++++++--------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 050d9a78fe..0730b59e70 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -37,7 +37,7 @@ hyper-rustls = "0.23.2" indicatif = "0.17.5" subprocess = "0.2.9" -axum = { version = "0.5.1", features = ["ws", "headers"] } +axum = { version = "0.6.20", features = ["ws", "headers"] } axum-server = { version = "0.5.1", features = ["tls-rustls"] } tower-http = { version = "0.2.2", features = ["full"] } headers = "0.3.7" diff --git a/packages/cli/src/cli/serve.rs b/packages/cli/src/cli/serve.rs index b4d60b7696..2f4d814027 100644 --- a/packages/cli/src/cli/serve.rs +++ b/packages/cli/src/cli/serve.rs @@ -33,9 +33,6 @@ impl Serve { crate_config.set_features(self.serve.features.unwrap()); } - // Subdirectories don't work with the server - crate_config.dioxus_config.web.app.base_path = None; - let platform = self .serve .platform diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 1c5bade15a..42a235f4aa 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -310,6 +310,21 @@ async fn setup_router( }, )); + router = if let Some(base_path) = config.dioxus_config.web.app.base_path.clone() { + let base_path = format!("/{}", base_path.trim_matches('/')); + Router::new() + .nest_service( + &base_path, + axum::routing::method_routing::any_service(router), + ) + .fallback(get(move || { + let base_path = base_path.clone(); + async move { format!("Outside of the base path: {}", base_path) } + })) + } else { + router + }; + // Setup routes router = router .route("/_dioxus/hot_reload", get(hot_reload_handler)) diff --git a/packages/router/src/history/web.rs b/packages/router/src/history/web.rs index 5b6ae0528e..a0f677e247 100644 --- a/packages/router/src/history/web.rs +++ b/packages/router/src/history/web.rs @@ -15,14 +15,13 @@ use super::{ #[allow(dead_code)] fn base_path() -> Option<&'static str> { - dioxus_cli_config::CURRENT_CONFIG.as_ref().ok().and_then(|c| { - c.dioxus_config - .web - .app - .base_path - .as_deref() - }) - } + let base_path = dioxus_cli_config::CURRENT_CONFIG + .as_ref() + .ok() + .and_then(|c| c.dioxus_config.web.app.base_path.as_deref()); + tracing::trace!("Using base_path from Dioxus.toml: {:?}", base_path); + base_path +} #[cfg(not(feature = "serde"))] #[allow(clippy::extra_unused_type_parameters)] @@ -171,12 +170,16 @@ impl WebHistory { .expect("`history` can set scroll restoration"); } + let prefix = prefix + .or_else(|| base_path().map(|s| s.to_string())) + .map(|prefix| format!("/{}", prefix.trim_matches('/'))); + Self { do_scroll_restoration, history, listener_navigation: None, listener_animation_frame: Default::default(), - prefix: prefix.or_else(||base_path().map(|s| s.to_string())), + prefix, window, phantom: Default::default(), } From 9bb464dd7d687cf72735b670786e5d92be5d5630 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 15 Nov 2023 09:29:15 -0600 Subject: [PATCH 11/17] fix cli tests --- packages/cli/Cargo.toml | 2 +- packages/cli/README.md | 8 ++++---- packages/cli/src/server/web/mod.rs | 4 ++-- packages/cli/src/server/web/proxy.rs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 0730b59e70..050d9a78fe 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -37,7 +37,7 @@ hyper-rustls = "0.23.2" indicatif = "0.17.5" subprocess = "0.2.9" -axum = { version = "0.6.20", features = ["ws", "headers"] } +axum = { version = "0.5.1", features = ["ws", "headers"] } axum-server = { version = "0.5.1", features = ["tls-rustls"] } tower-http = { version = "0.2.2", features = ["full"] } headers = "0.3.7" diff --git a/packages/cli/README.md b/packages/cli/README.md index 8379f22cc9..be053a2d2e 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -10,7 +10,7 @@ It handles building, bundling, development and publishing to simplify developmen ### Install the stable version (recommended) -``` +```sh cargo install dioxus-cli ``` @@ -20,7 +20,7 @@ To get the latest bug fixes and features, you can install the development versio However, this is not fully tested. That means you're probably going to have more bugs despite having the latest bug fixes. -``` +```sh cargo install --git https://github.com/DioxusLabs/dioxus dioxus-cli ``` @@ -29,7 +29,7 @@ and install it in Cargo's global binary directory (`~/.cargo/bin/` by default). ### Install from local folder -``` +```sh cargo install --path . --debug ``` @@ -40,7 +40,7 @@ It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxu Alternatively, you can specify the template path: -``` +```sh dx create hello --template gh:dioxuslabs/dioxus-template ``` diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 42a235f4aa..b38c535f49 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -313,9 +313,9 @@ async fn setup_router( router = if let Some(base_path) = config.dioxus_config.web.app.base_path.clone() { let base_path = format!("/{}", base_path.trim_matches('/')); Router::new() - .nest_service( + .nest( &base_path, - axum::routing::method_routing::any_service(router), + axum::routing::any_service(router), ) .fallback(get(move || { let base_path = base_path.clone(); diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index 4242a55eb0..d7b4837e8c 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -1,6 +1,6 @@ -use crate::Result; +use crate::{Result,}; use dioxus_cli_config::WebProxyConfig; - + use anyhow::Context; use axum::{http::StatusCode, routing::any, Router}; use hyper::{Request, Response, Uri}; From e11f3fdc484fb22a4983467d846c99479606227c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 15 Nov 2023 09:30:15 -0600 Subject: [PATCH 12/17] fix clippy --- packages/cli-config/src/lib.rs | 2 +- packages/cli/src/server/web/mod.rs | 5 +---- packages/cli/src/server/web/proxy.rs | 4 ++-- packages/core/src/diff.rs | 2 +- packages/rsx/src/lib.rs | 2 +- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index 776d1d10c2..da7446918e 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -47,7 +47,7 @@ pub static CURRENT_CONFIG: once_cell::sync::Lazy< Result, > = once_cell::sync::Lazy::new(|| { CURRENT_CONFIG_JSON - .and_then(|config| serde_json::from_str(&config).ok()) + .and_then(|config| serde_json::from_str(config).ok()) .ok_or_else(|| { tracing::error!("A library is trying to access the crate's configuration, but the dioxus CLI was not used to build the application."); DioxusCLINotUsed diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index b38c535f49..5ebc66772f 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -313,10 +313,7 @@ async fn setup_router( router = if let Some(base_path) = config.dioxus_config.web.app.base_path.clone() { let base_path = format!("/{}", base_path.trim_matches('/')); Router::new() - .nest( - &base_path, - axum::routing::any_service(router), - ) + .nest(&base_path, axum::routing::any_service(router)) .fallback(get(move || { let base_path = base_path.clone(); async move { format!("Outside of the base path: {}", base_path) } diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index d7b4837e8c..4242a55eb0 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -1,6 +1,6 @@ -use crate::{Result,}; +use crate::Result; use dioxus_cli_config::WebProxyConfig; - + use anyhow::Context; use axum::{http::StatusCode, routing::any, Router}; use hyper::{Request, Response, Uri}; diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 74017db0f9..b2145a806f 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -560,7 +560,7 @@ impl<'b> VirtualDom { // If none of the old keys are reused by the new children, then we remove all the remaining old children and // create the new children afresh. if shared_keys.is_empty() { - if old.get(0).is_some() { + if !old.is_empty() { self.remove_nodes(&old[1..]); self.replace(&old[0], new); } else { diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index bdf32b2721..5db6baee9b 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -193,7 +193,7 @@ impl<'a> ToTokens for TemplateRenderer<'a> { fn to_tokens(&self, out_tokens: &mut TokenStream2) { let mut context = DynamicContext::default(); - let key = match self.roots.get(0) { + let key = match self.roots.first() { Some(BodyNode::Element(el)) if self.roots.len() == 1 => el.key.clone(), Some(BodyNode::Component(comp)) if self.roots.len() == 1 => comp.key().cloned(), _ => None, From d51e9b60dfe22792554175428a27d191dab36b2a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 19 Nov 2023 11:16:15 -0600 Subject: [PATCH 13/17] make WebDevResourceConfig optional --- packages/cli-config/src/config.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs index fb3afb4ac8..0c99632226 100644 --- a/packages/cli-config/src/config.rs +++ b/packages/cli-config/src/config.rs @@ -181,11 +181,7 @@ impl Default for DioxusConfig { base_path: None, }, proxy: vec![], - watcher: WebWatcherConfig { - watch_path: watch_path_default(), - reload_html: false, - index_on_404: true, - }, + watcher: Default::default(), resource: WebResourceConfig { dev: WebDevResourceConfig { style: vec![], @@ -251,7 +247,9 @@ pub struct WebConfig { pub app: WebAppConfig, #[serde(default)] pub proxy: Vec, + #[serde(default)] pub watcher: WebWatcherConfig, + #[serde(default)] pub resource: WebResourceConfig, #[serde(default)] pub https: WebHttpsConfig, @@ -292,18 +290,28 @@ pub struct WebWatcherConfig { pub index_on_404: bool, } +impl Default for WebWatcherConfig { + fn default() -> Self { + Self { + watch_path: watch_path_default(), + reload_html: false, + index_on_404: true, + } + } +} + fn watch_path_default() -> Vec { vec![PathBuf::from("src"), PathBuf::from("examples")] } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct WebResourceConfig { pub dev: WebDevResourceConfig, pub style: Option>, pub script: Option>, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct WebDevResourceConfig { #[serde(default)] pub style: Vec, From 532ffaa614031aec4a8e0655484fa06d61343c84 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 20 Nov 2023 18:36:18 -0600 Subject: [PATCH 14/17] fix merge --- packages/cli/src/builder.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 40bc31d55e..4c9254bba4 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -460,13 +460,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool) -> String { &style.to_str().unwrap(), )) } - if config - .application - .tools - .clone() - .unwrap_or_default() - .contains_key("tailwindcss") - { + if config.application.tools.clone().contains_key("tailwindcss") { style_str.push_str("\n"); } From 4ff86d97637ceea6419a26b508bc33d8bfcf3d30 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 21 Nov 2023 13:11:49 -0600 Subject: [PATCH 15/17] make some extra dependencies only enabled for the CLI --- packages/cli-config/Cargo.toml | 14 ++++++------- packages/cli-config/src/config.rs | 35 +++++++++++++++++++------------ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml index 376dd32406..06d7adf497 100644 --- a/packages/cli-config/Cargo.toml +++ b/packages/cli-config/Cargo.toml @@ -9,18 +9,18 @@ license = "MIT OR Apache-2.0" keywords = ["react", "gui", "cli", "dioxus", "wasm"] [dependencies] -clap = { version = "4.2", features = ["derive"] } +clap = { version = "4.2", features = ["derive"], optional = true } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -toml = "0.5.8" -cargo_toml = "0.16.0" +toml = { version = "0.5.8", optional = true } +cargo_toml = { version = "0.16.0", optional = true } +once_cell = "1.18.0" +tracing.workspace = true # bundling -tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"], optional = true } +tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"], optional = true } tauri-utils = { version = "=1.4.*", optional = true } -once_cell = "1.18.0" -tracing.workspace = true [features] default = [] -cli = ["tauri-bundler", "tauri-utils"] +cli = ["tauri-bundler", "tauri-utils", "clap", "toml", "cargo_toml"] diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs index 0c99632226..ae76f53142 100644 --- a/packages/cli-config/src/config.rs +++ b/packages/cli-config/src/config.rs @@ -1,20 +1,16 @@ use crate::BundleConfig; use crate::CargoError; -use crate::{crate_root, Metadata}; -use clap::ValueEnum; use core::fmt::{Display, Formatter}; use serde::{Deserialize, Serialize}; -use std::{ - collections::HashMap, - path::{Path, PathBuf}, -}; +use std::path::PathBuf; -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Serialize, Deserialize, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)] +#[cfg_attr(feature = "cli", derive(clap::ValueEnum))] pub enum Platform { - #[clap(name = "web")] + #[cfg_attr(feature = "cli", clap(name = "web"))] #[serde(rename = "web")] Web, - #[clap(name = "desktop")] + #[cfg_attr(feature = "cli", clap(name = "desktop"))] #[serde(rename = "desktop")] Desktop, } @@ -28,10 +24,12 @@ pub struct DioxusConfig { #[serde(default)] pub bundle: BundleConfig, + #[cfg(feature = "cli")] #[serde(default = "default_plugin")] pub plugin: toml::Value, } +#[cfg(feature = "cli")] fn default_plugin() -> toml::Value { toml::Value::Boolean(true) } @@ -54,6 +52,7 @@ impl std::error::Error for LoadDioxusConfigError {} pub enum CrateConfigError { Cargo(CargoError), Io(std::io::Error), + #[cfg(feature = "cli")] Toml(toml::de::Error), LoadDioxusConfig(LoadDioxusConfigError), } @@ -70,6 +69,7 @@ impl From for CrateConfigError { } } +#[cfg(feature = "cli")] impl From for CrateConfigError { fn from(err: toml::de::Error) -> Self { Self::Toml(err) @@ -87,6 +87,7 @@ impl Display for CrateConfigError { match self { Self::Cargo(err) => write!(f, "{}", err), Self::Io(err) => write!(f, "{}", err), + #[cfg(feature = "cli")] Self::Toml(err) => write!(f, "{}", err), Self::LoadDioxusConfig(err) => write!(f, "{}", err), } @@ -96,6 +97,7 @@ impl Display for CrateConfigError { impl std::error::Error for CrateConfigError {} impl DioxusConfig { + #[cfg(feature = "cli")] /// Load the dioxus config from a path pub fn load(bin: Option) -> Result, CrateConfigError> { let crate_dir = crate::cargo::crate_root(); @@ -145,7 +147,8 @@ impl DioxusConfig { } } -fn acquire_dioxus_toml(dir: &Path) -> Option { +#[cfg(feature = "cli")] +fn acquire_dioxus_toml(dir: &std::path::Path) -> Option { // prefer uppercase let uppercase_conf = dir.join("Dioxus.toml"); if uppercase_conf.is_file() { @@ -171,6 +174,7 @@ impl Default for DioxusConfig { out_dir: out_dir_default(), asset_dir: asset_dir_default(), + #[cfg(feature = "cli")] tools: Default::default(), sub_package: None, @@ -202,6 +206,7 @@ impl Default for DioxusConfig { publisher: Some(name), ..Default::default() }, + #[cfg(feature = "cli")] plugin: toml::Value::Table(toml::map::Map::new()), } } @@ -218,8 +223,9 @@ pub struct ApplicationConfig { #[serde(default = "asset_dir_default")] pub asset_dir: PathBuf, + #[cfg(feature = "cli")] #[serde(default)] - pub tools: HashMap, + pub tools: std::collections::HashMap, #[serde(default)] pub sub_package: Option, @@ -334,6 +340,7 @@ pub struct CrateConfig { pub workspace_dir: PathBuf, pub target_dir: PathBuf, pub asset_dir: PathBuf, + #[cfg(feature = "cli")] pub manifest: cargo_toml::Manifest, pub executable: ExecutableType, pub dioxus_config: DioxusConfig, @@ -353,10 +360,11 @@ pub enum ExecutableType { } impl CrateConfig { + #[cfg(feature = "cli")] pub fn new(bin: Option) -> Result { let dioxus_config = DioxusConfig::load(bin.clone())?.unwrap_or_default(); - let crate_root = crate_root()?; + let crate_root = crate::crate_root()?; let crate_dir = if let Some(package) = &dioxus_config.application.sub_package { crate_root.join(package) @@ -366,7 +374,7 @@ impl CrateConfig { crate_root }; - let meta = Metadata::get()?; + let meta = crate::Metadata::get()?; let workspace_dir = meta.workspace_root; let target_dir = meta.target_directory; @@ -411,6 +419,7 @@ impl CrateConfig { workspace_dir, target_dir, asset_dir, + #[cfg(feature = "cli")] manifest, executable, release, From 0269a59c95e0bed83d2f6ce085c3ebc29ea9c683 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 8 Jan 2024 13:24:23 -0600 Subject: [PATCH 16/17] add fullstack platform --- packages/cli-config/src/config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs index ae76f53142..e6c828f7c9 100644 --- a/packages/cli-config/src/config.rs +++ b/packages/cli-config/src/config.rs @@ -13,6 +13,9 @@ pub enum Platform { #[cfg_attr(feature = "cli", clap(name = "desktop"))] #[serde(rename = "desktop")] Desktop, + #[cfg_attr(feature = "cli", clap(name = "fullstack"))] + #[serde(rename = "fullstack")] + Fullstack, } #[derive(Debug, Clone, Serialize, Deserialize)] From 2cc6f2f51f9a5d17b0327ea11752e5f699631630 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 8 Jan 2024 13:39:12 -0600 Subject: [PATCH 17/17] fix merge and reorganize the CLI a bit --- packages/cli-config/Cargo.toml | 4 +- packages/cli-config/src/bundle.rs | 1 + packages/cli-config/src/config.rs | 16 ++++++ packages/cli/Cargo.toml | 2 +- packages/cli/src/assets.rs | 60 +++++++++++++++++++++ packages/cli/src/builder.rs | 67 +++++------------------- packages/cli/src/cli/build.rs | 2 +- packages/cli/src/lib.rs | 1 + packages/cli/src/server/fullstack/mod.rs | 7 ++- packages/cli/src/server/mod.rs | 1 - 10 files changed, 100 insertions(+), 61 deletions(-) create mode 100644 packages/cli/src/assets.rs diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml index 06d7adf497..d6f422b3cf 100644 --- a/packages/cli-config/Cargo.toml +++ b/packages/cli-config/Cargo.toml @@ -18,8 +18,8 @@ once_cell = "1.18.0" tracing.workspace = true # bundling -tauri-bundler = { version = "=1.3.0", features = ["native-tls-vendored"], optional = true } -tauri-utils = { version = "=1.4.*", optional = true } +tauri-bundler = { version = "=1.4.0", features = ["native-tls-vendored"], optional = true } +tauri-utils = { version = "=1.5.*", optional = true } [features] default = [] diff --git a/packages/cli-config/src/bundle.rs b/packages/cli-config/src/bundle.rs index 4f44036d71..07c4fec213 100644 --- a/packages/cli-config/src/bundle.rs +++ b/packages/cli-config/src/bundle.rs @@ -200,6 +200,7 @@ impl From for tauri_bundler::NsisSettings { display_language_selector: val.display_language_selector, custom_language_files: None, template: None, + compression: None, } } } diff --git a/packages/cli-config/src/config.rs b/packages/cli-config/src/config.rs index e6c828f7c9..716b2bac47 100644 --- a/packages/cli-config/src/config.rs +++ b/packages/cli-config/src/config.rs @@ -353,6 +353,8 @@ pub struct CrateConfig { pub verbose: bool, pub custom_profile: Option, pub features: Option>, + pub target: Option, + pub cargo_args: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -415,6 +417,8 @@ impl CrateConfig { let verbose = false; let custom_profile = None; let features = None; + let target = None; + let cargo_args = vec![]; Ok(Self { out_dir, @@ -432,6 +436,8 @@ impl CrateConfig { custom_profile, features, verbose, + target, + cargo_args, }) } @@ -469,6 +475,16 @@ impl CrateConfig { self.features = Some(features); self } + + pub fn set_target(&mut self, target: String) -> &mut Self { + self.target = Some(target); + self + } + + pub fn set_cargo_args(&mut self, cargo_args: Vec) -> &mut Self { + self.cargo_args = cargo_args; + self + } } fn true_bool() -> bool { diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index bfb38db5cb..d22ac70311 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -76,7 +76,7 @@ toml_edit = "0.19.11" tauri-bundler = { version = "=1.4.*", features = ["native-tls-vendored"] } tauri-utils = "=1.5.*" -manganis-cli-support= { git = "https://github.com/DioxusLabs/collect-assets", features = ["webp", "html"] } +manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", features = ["webp", "html"] } dioxus-autofmt = { workspace = true } dioxus-check = { workspace = true } diff --git a/packages/cli/src/assets.rs b/packages/cli/src/assets.rs new file mode 100644 index 0000000000..081c1c85ce --- /dev/null +++ b/packages/cli/src/assets.rs @@ -0,0 +1,60 @@ +use std::{fs::File, io::Write, path::PathBuf}; + +use crate::Result; +use dioxus_cli_config::CrateConfig; +use manganis_cli_support::{AssetManifest, AssetManifestExt}; + +pub fn asset_manifest(crate_config: &CrateConfig) -> AssetManifest { + AssetManifest::load_from_path( + crate_config.crate_dir.join("Cargo.toml"), + crate_config.workspace_dir.join("Cargo.lock"), + ) +} + +/// Create a head file that contains all of the imports for assets that the user project uses +pub fn create_assets_head(config: &CrateConfig) -> Result<()> { + let manifest = asset_manifest(config); + let mut file = File::create(config.out_dir.join("__assets_head.html"))?; + file.write_all(manifest.head().as_bytes())?; + Ok(()) +} + +/// Process any assets collected from the binary +pub(crate) fn process_assets(config: &CrateConfig) -> anyhow::Result<()> { + let manifest = asset_manifest(config); + + let static_asset_output_dir = PathBuf::from( + config + .dioxus_config + .web + .app + .base_path + .clone() + .unwrap_or_default(), + ); + let static_asset_output_dir = config.out_dir.join(static_asset_output_dir); + + manifest.copy_static_assets_to(static_asset_output_dir)?; + + Ok(()) +} + +/// A guard that sets up the environment for the web renderer to compile in. This guard sets the location that assets will be served from +pub(crate) struct WebAssetConfigDropGuard; + +impl WebAssetConfigDropGuard { + pub fn new() -> Self { + // Set up the collect asset config + manganis_cli_support::Config::default() + .with_assets_serve_location("/") + .save(); + Self {} + } +} + +impl Drop for WebAssetConfigDropGuard { + fn drop(&mut self) { + // Reset the config + manganis_cli_support::Config::default().save(); + } +} diff --git a/packages/cli/src/builder.rs b/packages/cli/src/builder.rs index 5a67830201..bed60ff5a0 100644 --- a/packages/cli/src/builder.rs +++ b/packages/cli/src/builder.rs @@ -1,19 +1,18 @@ use crate::{ + assets::{asset_manifest, create_assets_head, process_assets, WebAssetConfigDropGuard}, error::{Error, Result}, tools::Tool, }; use cargo_metadata::{diagnostic::Diagnostic, Message}; use dioxus_cli_config::crate_root; use dioxus_cli_config::CrateConfig; -use dioxus_cli_config::DioxusConfig; use dioxus_cli_config::ExecutableType; use indicatif::{ProgressBar, ProgressStyle}; use lazy_static::lazy_static; -use manganis_cli_support::AssetManifestExt; use serde::Serialize; use std::{ fs::{copy, create_dir_all, File}, - io::{Read, Write}, + io::Read, panic, path::PathBuf, time::Duration, @@ -415,13 +414,6 @@ pub fn build_desktop( }) } -fn create_assets_head(config: &CrateConfig) -> Result<()> { - let manifest = config.asset_manifest(); - let mut file = File::create(config.out_dir.join("__assets_head.html"))?; - file.write_all(manifest.head().as_bytes())?; - Ok(()) -} - fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result> { let mut warning_messages: Vec = vec![]; @@ -478,10 +470,10 @@ fn prettier_build(cmd: subprocess::Exec) -> anyhow::Result> { Ok(warning_messages) } -pub fn gen_page(config: &DioxusConfig, serve: bool, skip_assets: bool) -> String { +pub fn gen_page(config: &CrateConfig, serve: bool, skip_assets: bool) -> String { let _gaurd = WebAssetConfigDropGuard::new(); - let crate_root = crate::cargo::crate_root().unwrap(); + let crate_root = crate_root().unwrap(); let custom_html_file = crate_root.join("index.html"); let mut html = if custom_html_file.is_file() { let mut buf = String::new(); @@ -514,11 +506,17 @@ pub fn gen_page(config: &DioxusConfig, serve: bool, skip_assets: bool) -> String &style.to_str().unwrap(), )) } - if config.application.tools.clone().contains_key("tailwindcss") { + if config + .dioxus_config + .application + .tools + .clone() + .contains_key("tailwindcss") + { style_str.push_str("\n"); } if !skip_assets { - let manifest = config.asset_manifest(); + let manifest = asset_manifest(config); style_str.push_str(&manifest.head()); } @@ -569,7 +567,7 @@ pub fn gen_page(config: &DioxusConfig, serve: bool, skip_assets: bool) -> String ); } - let title = config.web.app.title.clone(); + let title = config.dioxus_config.web.app.title.clone(); replace_or_insert_before("{app_title}", &title, " Result> { Ok(result) } - -/// Process any assets collected from the binary -fn process_assets(config: &CrateConfig) -> anyhow::Result<()> { - let manifest = config.asset_manifest(); - - let static_asset_output_dir = PathBuf::from( - config - .dioxus_config - .web - .app - .base_path - .clone() - .unwrap_or_default(), - ); - let static_asset_output_dir = config.out_dir.join(static_asset_output_dir); - - manifest.copy_static_assets_to(static_asset_output_dir)?; - - Ok(()) -} - -pub(crate) struct WebAssetConfigDropGuard; - -impl WebAssetConfigDropGuard { - pub fn new() -> Self { - // Set up the collect asset config - manganis_cli_support::Config::default() - .with_assets_serve_location("/") - .save(); - Self {} - } -} - -impl Drop for WebAssetConfigDropGuard { - fn drop(&mut self) { - // Reset the config - manganis_cli_support::Config::default().save(); - } -} diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 3b48ec6902..fb0bdfb240 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -1,8 +1,8 @@ +use crate::assets::WebAssetConfigDropGuard; #[cfg(feature = "plugin")] use crate::plugin::PluginManager; use crate::server::fullstack::FullstackServerEnvGuard; use crate::server::fullstack::FullstackWebEnvGuard; -use crate::WebAssetConfigDropGuard; use dioxus_cli_config::Platform; use super::*; diff --git a/packages/cli/src/lib.rs b/packages/cli/src/lib.rs index 63ec1fac05..191c65008e 100644 --- a/packages/cli/src/lib.rs +++ b/packages/cli/src/lib.rs @@ -4,6 +4,7 @@ pub const DIOXUS_CLI_VERSION: &str = "0.4.1"; +mod assets; pub mod builder; pub mod server; pub mod tools; diff --git a/packages/cli/src/server/fullstack/mod.rs b/packages/cli/src/server/fullstack/mod.rs index fa9c774597..60d685ceda 100644 --- a/packages/cli/src/server/fullstack/mod.rs +++ b/packages/cli/src/server/fullstack/mod.rs @@ -1,6 +1,9 @@ +use dioxus_cli_config::CrateConfig; + use crate::{ + assets::WebAssetConfigDropGuard, cfg::{ConfigOptsBuild, ConfigOptsServe}, - CrateConfig, Result, WebAssetConfigDropGuard, + Result, }; use super::{desktop, Platform}; @@ -86,7 +89,7 @@ fn build_web(serve: ConfigOptsServe, target_directory: &std::path::Path) -> Resu } None => web_config.features = Some(vec![web_feature]), }; - web_config.platform = Some(crate::cfg::Platform::Web); + web_config.platform = Some(dioxus_cli_config::Platform::Web); let _gaurd = FullstackWebEnvGuard::new(&web_config); crate::cli::build::Build { build: web_config }.build(None, Some(target_directory)) diff --git a/packages/cli/src/server/mod.rs b/packages/cli/src/server/mod.rs index e995e575ec..1fe5f2ea58 100644 --- a/packages/cli/src/server/mod.rs +++ b/packages/cli/src/server/mod.rs @@ -1,5 +1,4 @@ use crate::{cfg::ConfigOptsServe, BuildResult, Result}; -use crate::{BuildResult, Result}; use dioxus_cli_config::CrateConfig; use cargo_metadata::diagnostic::Diagnostic;