diff --git a/Cargo.lock b/Cargo.lock index 2d15497d2..2e4f1da81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5021,6 +5021,7 @@ dependencies = [ "axum_session", "axum_session_auth", "dioxus", + "dioxus-cli-config", "dioxus-fullstack", "dioxus-web", "execute", diff --git a/examples/fullstack-auth/src/main.rs b/examples/fullstack-auth/src/main.rs index 7408b24bc..e872003e5 100644 --- a/examples/fullstack-auth/src/main.rs +++ b/examples/fullstack-auth/src/main.rs @@ -63,8 +63,8 @@ fn main() { ) .layer(axum_session::SessionLayer::new(session_store)); - // run it - let addr = dioxus_cli_config::fullstack_address_or_localhost(); + // serve the app using the address passed by the CLI + let addr = dioxus::cli_config::fullstack_address_or_localhost(); let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); axum::serve(listener, app.into_make_service()) diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index 3d53303c0..0e413a54f 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -1,3 +1,56 @@ +//!
+//! Build web, desktop, and mobile apps with a single codebase. +//!
+//! +//! # Dioxus CLI configuration +//! +//! This crate exposes the various configuration options that the Dioxus CLI sets when running the +//! application during development. +//! +//! Note that these functions will return a different value when running under the CLI, so make sure +//! not to rely on them when running in a production environment. +//! +//! ## Constants +//! +//! The various constants here are the names of the environment variables that the CLI sets. We recommend +//! using the functions in this crate to access the values of these environment variables indirectly. +//! +//! The CLI uses this crate and the associated constants to *set* the environment variables, but as +//! a consumer of the CLI, you would want to read the values of these environment variables using +//! the provided functions. +//! +//! ## Example Usage +//! +//! We recommend using the functions here to access the values of the environment variables set by the CLI. +//! For example, you might use the [`fullstack_address_or_localhost`] function to get the address that +//! the CLI is requesting the application to be served on. +//! +//! ```rust, ignore +//! async fn launch_axum(app: axum::Router<()>) { +//! // Read the PORT and ADDR environment variables set by the CLI +//! let addr = dioxus_cli_config::fullstack_address_or_localhost(); +//! +//! // Bind to the address and serve the application +//! let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); +//! axum::serve(listener, app.into_make_service()) +//! .await +//! .unwrap(); +//! } +//! ``` +//! +//! ## Stability +//! +//! The *values* that these functions return are *not* guaranteed to be stable between patch releases +//! of Dioxus. At any time, we might change the values that the CLI sets or the way that they are read. +//! +//! We also don't guarantee the stability of the env var names themselves. If you want to rely on a +//! particular env var, use the defined constants in your code. + use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, path::PathBuf, @@ -10,6 +63,9 @@ pub const DEVSERVER_RAW_ADDR_ENV: &str = "DIOXUS_DEVSERVER_ADDR"; pub const ALWAYS_ON_TOP_ENV: &str = "DIOXUS_ALWAYS_ON_TOP"; pub const ASSET_ROOT_ENV: &str = "DIOXUS_ASSET_ROOT"; pub const APP_TITLE_ENV: &str = "DIOXUS_APP_TITLE"; + +#[deprecated(since = "0.6.0", note = "The CLI currently does not set this.")] +#[doc(hidden)] pub const OUT_DIR: &str = "DIOXUS_OUT_DIR"; /// Reads an environment variable at runtime in debug mode or at compile time in @@ -37,7 +93,11 @@ macro_rules! read_env_config { /// Get the address of the devserver for use over a raw socket /// -/// This is not a websocket! There's no protocol! +/// This returns a [`SocketAddr`], meaning that you still need to connect to it using a socket with +/// the appropriate protocol and path. +/// +/// For reference, the devserver typically lives on `127.0.0.1:8080` and serves the devserver websocket +/// on `127.0.0.1:8080/_dioxus`. pub fn devserver_raw_addr() -> Option { // On android, 10.0.2.2 is the default loopback if cfg!(target_os = "android") { @@ -50,59 +110,110 @@ pub fn devserver_raw_addr() -> Option { .flatten() } +/// Get the address of the devserver for use over a websocket +/// +/// This is meant for internal use, though if you are building devtools around Dioxus, this would be +/// useful to connect as a "listener" to the devserver. +/// +/// Unlike [`devserver_raw_addr`], this returns a string that can be used directly to connect to the +/// devserver over a websocket. IE `ws://127.0.0.1:8080/_dioxus`. pub fn devserver_ws_endpoint() -> Option { let addr = devserver_raw_addr()?; Some(format!("ws://{addr}/_dioxus")) } +/// Get the IP that the server should be bound to. +/// +/// This is set by the CLI and is used to bind the server to a specific address. +/// You can manually set the ip by setting the `IP` environment variable. +/// +/// ```sh +/// IP=0.0.0.0 ./server +/// ``` pub fn server_ip() -> Option { std::env::var(SERVER_IP_ENV) .ok() .and_then(|s| s.parse().ok()) } +/// Get the port that the server should listen on. +/// +/// This is set by the CLI and is used to bind the server to a specific port. +/// You can manually set the port by setting the `PORT` environment variable. +/// +/// ```sh +/// PORT=8081 ./server +/// ``` pub fn server_port() -> Option { std::env::var(SERVER_PORT_ENV) .ok() .and_then(|s| s.parse().ok()) } +/// Get the full address that the server should listen on. +/// +/// This is a convenience function that combines the `server_ip` and `server_port` functions and then +/// falls back to `localhost:8080` if the environment variables are not set. +/// +/// ## Example +/// +/// ```rust, ignore +/// async fn launch_axum(app: axum::Router<()>) { +/// // Read the PORT and ADDR environment variables set by the CLI +/// let addr = dioxus_cli_config::fullstack_address_or_localhost(); +/// +/// // Bind to the address and serve the application +/// let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); +/// axum::serve(listener, app.into_make_service()) +/// .await +/// .unwrap(); +/// } +/// ``` +/// +/// ## Stability +/// +/// In the future, we might change the address from 127.0.0.1 to 0.0.0.0. pub fn fullstack_address_or_localhost() -> SocketAddr { let ip = server_ip().unwrap_or_else(|| IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); let port = server_port().unwrap_or(8080); SocketAddr::new(ip, port) } +/// Get the title of the application, usually set by the Dioxus.toml. +/// +/// This is used to set the title of the desktop window if the app itself doesn't set it. pub fn app_title() -> Option { read_env_config!("DIOXUS_APP_TITLE") } +/// Check if the application should forced to "float" on top of other windows. +/// +/// The CLI sets this based on the `--always-on-top` flag and the settings system. pub fn always_on_top() -> Option { std::env::var(ALWAYS_ON_TOP_ENV) .ok() .and_then(|s| s.parse().ok()) } +/// Check if the CLI is enabled when running the application. +/// +/// The CLI *always* sets this value to true when running the application. +/// +/// ## Note +/// +/// On Android and the Web, this *might* not be reliable since there isn't always a consistent way to +/// pass off the CLI environment variables to the application. pub fn is_cli_enabled() -> bool { + // todo: (jon) - on android and web we should fix this... std::env::var(CLI_ENABLED_ENV).is_ok() } -#[cfg(feature = "web")] -#[wasm_bindgen::prelude::wasm_bindgen(inline_js = r#" - export function getMetaContents(meta_name) { - const selector = document.querySelector(`meta[name="${meta_name}"]`); - if (!selector) { - return null; - } - return selector.content; - } -"#)] -extern "C" { - #[wasm_bindgen(js_name = getMetaContents)] - pub fn get_meta_contents(selector: &str) -> Option; -} - -/// Get the path where the application will be served from. This is used by the router to format the URLs. +/// Get the path where the application will be served from. +/// +/// This is used by the router to format the URLs. For example, an app with a base path of `dogapp` will +/// be served at `http://localhost:8080/dogapp`. +/// +/// All assets will be served from this base path as well, ie `http://localhost:8080/dogapp/assets/logo.png`. pub fn base_path() -> Option { // This may trigger when compiling to the server if you depend on another crate that pulls in // the web feature. It might be better for the renderers to provide the current platform @@ -115,7 +226,24 @@ pub fn base_path() -> Option { read_env_config!("DIOXUS_ASSET_ROOT") } +#[cfg(feature = "web")] +#[wasm_bindgen::prelude::wasm_bindgen(inline_js = r#" + export function getMetaContents(meta_name) { + const selector = document.querySelector(`meta[name="${meta_name}"]`); + if (!selector) { + return null; + } + return selector.content; + } + "#)] +extern "C" { + #[wasm_bindgen(js_name = getMetaContents)] + pub fn get_meta_contents(selector: &str) -> Option; +} + /// Get the path where the application is served from in the browser. +/// +/// This uses wasm_bindgen on the browser to extract the base path from a meta element. #[cfg(feature = "web")] pub fn web_base_path() -> Option { // In debug mode, we get the base path from the meta element which can be hot reloaded and changed without recompiling @@ -134,10 +262,23 @@ pub fn web_base_path() -> Option { } } +/// Format a meta element for the base path to be used in the output HTML +#[doc(hidden)] pub fn format_base_path_meta_element(base_path: &str) -> String { format!(r#""#,) } +/// Get the path to the output directory where the application is being built. +/// +/// This might not return a valid path - we don't recommend relying on this. +#[doc(hidden)] +#[deprecated( + since = "0.6.0", + note = "The does not set the OUT_DIR environment variable." +)] pub fn out_dir() -> Option { - std::env::var(OUT_DIR).ok().map(PathBuf::from) + #[allow(deprecated)] + { + std::env::var(OUT_DIR).ok().map(PathBuf::from) + } } diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml index 758d3f046..692484a11 100644 --- a/packages/dioxus/Cargo.toml +++ b/packages/dioxus/Cargo.toml @@ -37,7 +37,7 @@ dioxus-cli-config = { workspace = true, optional = true } dioxus-devtools = { workspace = true, optional = true } [features] -default = ["macro", "html", "signals", "hooks", "launch", "mounted", "file_engine", "document", "asset", "devtools", "logger", "warnings"] +default = ["macro", "html", "signals", "hooks", "launch", "mounted", "file_engine", "document", "asset", "devtools", "logger", "warnings", "cli-config"] minimal = ["macro", "html", "signals", "hooks", "launch"] signals = ["dep:dioxus-signals"] macro = ["dep:dioxus-core-macro"] @@ -49,6 +49,7 @@ file_engine = ["dioxus-web?/file_engine"] asset = ["dep:manganis"] document = ["dioxus-web?/document", "dep:dioxus-document", "dep:dioxus-history"] logger = ["dep:dioxus-logger"] +cli-config = ["dep:dioxus-cli-config"] warnings = ["dep:warnings"] launch = ["dep:dioxus-config-macro"] @@ -58,7 +59,7 @@ router = ["dep:dioxus-router"] fullstack = ["dep:dioxus-fullstack", "dioxus-config-macro/fullstack", "dep:serde"] desktop = ["dep:dioxus-desktop", "dioxus-fullstack?/desktop", "dioxus-config-macro/desktop"] mobile = ["dep:dioxus-mobile", "dioxus-fullstack?/mobile", "dioxus-config-macro/mobile"] -web = ["dep:dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web", "dioxus-cli-config", "dioxus-cli-config/web"] +web = ["dep:dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web", "dep:dioxus-cli-config", "dioxus-cli-config?/web"] ssr = ["dep:dioxus-ssr", "dioxus-config-macro/ssr"] liveview = ["dep:dioxus-liveview", "dioxus-config-macro/liveview"] server = ["dioxus-fullstack?/axum", "dioxus-fullstack?/server", "ssr", "dioxus-liveview?/axum"] diff --git a/packages/dioxus/src/lib.rs b/packages/dioxus/src/lib.rs index 320d5ca4c..1bfa4f484 100644 --- a/packages/dioxus/src/lib.rs +++ b/packages/dioxus/src/lib.rs @@ -70,6 +70,10 @@ pub use dioxus_core_macro as core_macro; #[cfg_attr(docsrs, doc(cfg(feature = "logger")))] pub use dioxus_logger as logger; +#[cfg(feature = "cli-config")] +#[cfg_attr(docsrs, doc(cfg(feature = "cli-config")))] +pub use dioxus_cli_config as cli_config; + pub mod prelude { #[cfg(feature = "document")] #[cfg_attr(docsrs, doc(cfg(feature = "document")))] diff --git a/packages/fullstack/README.md b/packages/fullstack/README.md index 86a36ba8d..21dfb0e1f 100644 --- a/packages/fullstack/README.md +++ b/packages/fullstack/README.md @@ -93,7 +93,7 @@ use dioxus::prelude::*; async fn main() { // Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address // and we use the generated address the CLI gives us - let address = dioxus_cli_config::fullstack_address_or_localhost(); + let address = dioxus::cli_config::fullstack_address_or_localhost(); // Set up the axum router let router = axum::Router::new() diff --git a/packages/fullstack/src/server/mod.rs b/packages/fullstack/src/server/mod.rs index a53647dee..a5993838e 100644 --- a/packages/fullstack/src/server/mod.rs +++ b/packages/fullstack/src/server/mod.rs @@ -16,7 +16,7 @@ //! .block_on(async move { //! // Get the address the server should run on. If the CLI is running, the CLI proxies fullstack into the main address //! // and we use the generated address the CLI gives us -//! let address = dioxus_cli_config::fullstack_address_or_localhost(); +//! let address = dioxus::cli_config::fullstack_address_or_localhost(); //! let listener = tokio::net::TcpListener::bind(address) //! .await //! .unwrap(); @@ -85,7 +85,7 @@ pub trait DioxusRouterExt { /// # use dioxus_fullstack::prelude::*; /// #[tokio::main] /// async fn main() { - /// let addr = dioxus_cli_config::fullstack_address_or_localhost(); + /// let addr = dioxus::cli_config::fullstack_address_or_localhost(); /// let router = axum::Router::new() /// // Register server functions routes with the default handler /// .register_server_functions() @@ -110,7 +110,7 @@ pub trait DioxusRouterExt { /// # use std::sync::Arc; /// #[tokio::main] /// async fn main() { - /// let addr = dioxus_cli_config::fullstack_address_or_localhost(); + /// let addr = dioxus::cli_config::fullstack_address_or_localhost(); /// let router = axum::Router::new() /// // Register server functions routes with the default handler /// .register_server_functions_with_context(Arc::new(vec![Box::new(|| Box::new(1234567890u32))])) @@ -130,7 +130,7 @@ pub trait DioxusRouterExt { /// # use dioxus_fullstack::prelude::*; /// #[tokio::main] /// async fn main() { - /// let addr = dioxus_cli_config::fullstack_address_or_localhost(); + /// let addr = dioxus::cli_config::fullstack_address_or_localhost(); /// let router = axum::Router::new() /// // Server side render the application, serve static assets, and register server functions /// .serve_static_assets() @@ -155,7 +155,7 @@ pub trait DioxusRouterExt { /// # use dioxus_fullstack::prelude::*; /// #[tokio::main] /// async fn main() { - /// let addr = dioxus_cli_config::fullstack_address_or_localhost(); + /// let addr = dioxus::cli_config::fullstack_address_or_localhost(); /// let router = axum::Router::new() /// // Server side render the application, serve static assets, and register server functions /// .serve_dioxus_application(ServeConfig::new().unwrap(), app) @@ -361,7 +361,7 @@ impl RenderHandleState { /// /// #[tokio::main] /// async fn main() { -/// let addr = dioxus_cli_config::fullstack_address_or_localhost(); +/// let addr = dioxus::cli_config::fullstack_address_or_localhost(); /// let router = axum::Router::new() /// // Register server functions, etc. /// // Note you can use `register_server_functions_with_context`