dioxus_cli_config/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
//! <div align="center">
//! <img
//! src="https://github.com/user-attachments/assets/6c7e227e-44ff-4e53-824a-67949051149c"
//! alt="Build web, desktop, and mobile apps with a single codebase."
//! width="100%"
//! class="darkmode-image"
//! >
//! </div>
//!
//! # 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,
};
pub const CLI_ENABLED_ENV: &str = "DIOXUS_CLI_ENABLED";
pub const SERVER_IP_ENV: &str = "IP";
pub const SERVER_PORT_ENV: &str = "PORT";
pub const DEVSERVER_IP_ENV: &str = "DIOXUS_DEVSERVER_IP";
pub const DEVSERVER_PORT_ENV: &str = "DIOXUS_DEVSERVER_PORT";
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";
pub const SESSION_CACHE_DIR: &str = "DIOXUS_SESSION_CACHE_DIR";
/// Reads an environment variable at runtime in debug mode or at compile time in
/// release mode. When bundling in release mode, we will not be running under the
/// environment variables that the CLI sets, so we need to read them at compile time.
macro_rules! read_env_config {
($name:expr) => {{
#[cfg(debug_assertions)]
{
// In debug mode, read the environment variable set by the CLI at runtime
std::env::var($name).ok()
}
#[cfg(not(debug_assertions))]
{
// In release mode, read the environment variable set by the CLI at compile time
// This means the value will still be available when running the application
// standalone.
// We don't always read the environment variable at compile time to avoid rebuilding
// this crate when the environment variable changes.
option_env!($name).map(ToString::to_string)
}
}};
}
/// Get the address of the devserver for use over a raw socket
///
/// 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<SocketAddr> {
let ip = std::env::var(DEVSERVER_IP_ENV).ok()?;
let port = std::env::var(DEVSERVER_PORT_ENV).ok()?;
if cfg!(target_os = "android") {
// Since `adb reverse` is used for Android, the 127.0.0.1 will always be
// the correct IP address.
return Some(format!("127.0.0.1:{}", port).parse().unwrap());
}
format!("{}:{}", ip, port).parse().ok()
}
/// 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<String> {
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<IpAddr> {
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<u16> {
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<String> {
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<bool> {
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()
}
/// 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<String> {
// 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
// as a global context
#[cfg(all(feature = "web", target_arch = "wasm32"))]
{
return web_base_path();
}
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<String>;
}
/// 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<String> {
// In debug mode, we get the base path from the meta element which can be hot reloaded and changed without recompiling
#[cfg(debug_assertions)]
{
thread_local! {
static BASE_PATH: std::cell::OnceCell<Option<String>> = const { std::cell::OnceCell::new() };
}
BASE_PATH.with(|f| f.get_or_init(|| get_meta_contents(ASSET_ROOT_ENV)).clone())
}
// In release mode, we get the base path from the environment variable
#[cfg(not(debug_assertions))]
{
option_env!("DIOXUS_ASSET_ROOT").map(ToString::to_string)
}
}
/// 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#"<meta name="{ASSET_ROOT_ENV}" content="{base_path}">"#,)
}
/// 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<PathBuf> {
#[allow(deprecated)]
{
std::env::var(OUT_DIR).ok().map(PathBuf::from)
}
}
/// Get the directory where this app can write to for this session that's guaranteed to be stable
/// between reloads of the same app. This is useful for emitting state like window position and size
/// so the app can restore it when it's next opened.
///
/// Note that this cache dir is really only useful for platforms that can access it. Web/Android
/// don't have access to this directory, so it's not useful for them.
///
/// This is designed with desktop executables in mind.
pub fn session_cache_dir() -> Option<PathBuf> {
if cfg!(target_os = "android") {
return Some(android_session_cache_dir());
}
std::env::var(SESSION_CACHE_DIR).ok().map(PathBuf::from)
}
/// The session cache directory for android
pub fn android_session_cache_dir() -> PathBuf {
PathBuf::from("/data/local/tmp/dx/")
}