Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5905bce
Add --renderer argument to the CLI
nicoburns Jun 24, 2025
0f0826f
Make `--platform native` work
nicoburns Jun 30, 2025
6332252
Emit `krates` error when cargo metadata fails
jkelleyrtp Jul 1, 2025
c806365
Reinstate default "desktop" feature for examples
nicoburns Jul 2, 2025
72a32a0
Remove commented 'no platform specified' error
nicoburns Jul 2, 2025
51b259b
use the target tripple and bundle format as the source of truth for t…
ealmloff Jul 8, 2025
59dc4d0
resolve renderer and bundle format
ealmloff Jul 8, 2025
4594dff
add shorthand flags
ealmloff Jul 8, 2025
11b1539
add headings to the help for shorthands
ealmloff Jul 8, 2025
40ae4e7
Merge branch 'remote-origin' into cli-renderer-flag
ealmloff Jul 8, 2025
f77f371
resolve the renderer from the target triple if it isn't passed
ealmloff Jul 8, 2025
cef67e7
make value after --fullstack optional
ealmloff Jul 8, 2025
a073579
convert desktop -> mobile when targeting mobile webview
ealmloff Jul 8, 2025
e01dc1d
use the new shorthand flags in the playwright tests
ealmloff Jul 8, 2025
e2a6677
fix clippy
ealmloff Jul 8, 2025
79ce1c2
Merge remote-tracking branch 'origin/main' into cli-renderer-flag
jkelleyrtp Jul 14, 2025
c5851ed
merge fix
jkelleyrtp Jul 14, 2025
256153b
cleanup merge conflicts
jkelleyrtp Jul 14, 2025
bd28449
fix clippy
ealmloff Jul 14, 2025
e11ff9b
Merge remote-tracking branch 'origin/main' into cli-renderer-flag
jkelleyrtp Jul 15, 2025
860d3de
remove nit
jkelleyrtp Jul 15, 2025
0c78865
restore platform as a legacy argument
ealmloff Jul 21, 2025
2d6f796
improve help message
ealmloff Jul 21, 2025
873ccf5
Merge branch 'remote-origin' into cli-renderer-flag
ealmloff Jul 21, 2025
ec0f180
vendor openssl on native, pin server_fn
jkelleyrtp Jul 22, 2025
0b9eb8c
print build errors as warnings
jkelleyrtp Jul 22, 2025
081c1a7
add --desktop arg compat
jkelleyrtp Jul 22, 2025
84e3685
adjust cli headings
jkelleyrtp Jul 22, 2025
b4c2af6
prefer self.is_wasm_or_wasi()
jkelleyrtp Jul 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,6 @@ openssl = { version = "0.10", features = ["vendored"] }
# To make most examples faster to compile, we split out assets and http-related stuff
# This trims off like 270 dependencies, leading to a significant speedup in compilation time
[features]
default = ["desktop"]
desktop = ["dioxus/desktop"]
native = ["dioxus/native"]
liveview = ["dioxus/liveview"]
Expand Down
45 changes: 33 additions & 12 deletions packages/cli/src/build/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@
//! - xbuild: <https://github.com/rust-mobile/xbuild/blob/master/xbuild/src/command/build.rs>

use crate::{
AndroidTools, BuildContext, DioxusConfig, Error, LinkAction, LinkerFlavor, Platform, Result,
RustcArgs, TargetArgs, TraceSrc, WasmBindgen, WasmOptConfig, Workspace,
DX_RUSTC_WRAPPER_ENV_VAR,
AndroidTools, BuildContext, ClientRenderer, DioxusConfig, Error, LinkAction, LinkerFlavor,
Platform, PlatformArg, Result, RustcArgs, TargetArgs, TraceSrc, WasmBindgen, WasmOptConfig,
Workspace, DX_RUSTC_WRAPPER_ENV_VAR,
};
use anyhow::Context;
use cargo_metadata::diagnostic::Diagnostic;
Expand Down Expand Up @@ -552,24 +552,36 @@ impl BuildRequest {
.iter()
.any(|dep| dep.name == "dioxus");

// Infer the renderer from platform argument if the platform argument is "native" or "desktop"
let renderer = args.renderer.or(match args.platform {
Some(PlatformArg::Desktop) => Some(ClientRenderer::Webview),
Some(PlatformArg::Native) => Some(ClientRenderer::Native),
_ => None,
});

let mut features = args.features.clone();
let mut no_default_features = args.no_default_features;

let platform: Platform = match args.platform {
Some(platform) => match enabled_platforms.len() {
0 => platform,
Some(platform_arg) => match enabled_platforms.len() {
0 => Platform::from(platform_arg),

// The user passed --platform XYZ but already has `default = ["ABC"]` in their Cargo.toml or dioxus = { features = ["abc"] }
// We want to strip out the default platform and use the one they passed, setting no-default-features
_ => {
features.extend(Self::platformless_features(main_package));
no_default_features = true;
platform
Platform::from(platform_arg)
}
},
None if !using_dioxus_explicitly => Platform::autodetect_from_cargo_feature("desktop").unwrap(),
None if !using_dioxus_explicitly => Platform::TARGET_PLATFORM.unwrap(),
None => match enabled_platforms.len() {
0 => return Err(anyhow::anyhow!("No platform specified and no platform marked as default in Cargo.toml. Try specifying a platform with `--platform`").into()),
0 => match renderer {
Some(_) => Platform::TARGET_PLATFORM.unwrap(),
None => Platform::TARGET_PLATFORM.unwrap(),
// TODO: should we always have a default
// None => return Err(anyhow::anyhow!("No platform specified and no platform marked as default in Cargo.toml. Try specifying a platform with `--platform`").into()),
},
1 => enabled_platforms[0],
_ => {
return Err(anyhow::anyhow!(
Expand All @@ -582,7 +594,11 @@ impl BuildRequest {

// Add any features required to turn on the client
if using_dioxus_explicitly {
features.push(Self::feature_for_platform(main_package, platform));
features.push(Self::feature_for_platform_and_renderer(
main_package,
platform,
renderer,
));
}

// Set the profile of the build if it's not already set
Expand Down Expand Up @@ -2867,9 +2883,13 @@ impl BuildRequest {
}

/// Get the features required to build for the given platform
fn feature_for_platform(package: &krates::cm::Package, platform: Platform) -> String {
fn feature_for_platform_and_renderer(
package: &krates::cm::Package,
platform: Platform,
renderer: Option<ClientRenderer>,
) -> String {
// Try to find the feature that activates the dioxus feature for the given platform
let dioxus_feature = platform.feature_name();
let dioxus_feature = platform.feature_name(renderer);

let res = package.features.iter().find_map(|(key, features)| {
// if the feature is just the name of the platform, we use that
Expand All @@ -2895,7 +2915,7 @@ impl BuildRequest {
});

res.unwrap_or_else(|| {
let fallback = format!("dioxus/{}", platform.feature_name()) ;
let fallback = format!("dioxus/{}", dioxus_feature) ;
tracing::debug!(
"Could not find explicit feature for platform {platform}, passing `fallback` instead"
);
Expand Down Expand Up @@ -2953,6 +2973,7 @@ impl BuildRequest {
};

// we only trace features 1 level deep..
// TODO: trace all enabled features, not just default features
for feature in default.iter() {
// If the user directly specified a platform we can just use that.
if feature.starts_with("dioxus/") {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/cli/build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{cli::*, AppBuilder, BuildRequest, Workspace};
use crate::{BuildMode, Platform};
use crate::{BuildMode, Platform, PlatformArg};

use super::target::TargetArgs;

Expand Down Expand Up @@ -120,7 +120,7 @@ impl CommandWithPlatformOverrides<BuildArgs> {
let main_target = client.main_target.clone();
let mut server_args = server_args.clone();
// The platform in the server build is always set to Server
server_args.platform = Some(Platform::Server);
server_args.platform = Some(PlatformArg::Server);
server =
Some(BuildRequest::new(&server_args, Some(main_target), workspace.clone()).await?);
}
Expand Down
9 changes: 7 additions & 2 deletions packages/cli/src/cli/target.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cli::*;
use crate::Platform;
use crate::ClientRenderer;
use crate::PlatformArg;
use target_lexicon::Triple;

const HELP_HEADING: &str = "Target Options";
Expand All @@ -9,7 +10,11 @@ const HELP_HEADING: &str = "Target Options";
pub(crate) struct TargetArgs {
/// Build platform: support Web & Desktop [default: "default_platform"]
#[clap(long, value_enum, help_heading = HELP_HEADING)]
pub(crate) platform: Option<Platform>,
pub(crate) platform: Option<PlatformArg>,

/// Build renderer: support Webview and Native [default: "webview"]
#[clap(long, value_enum, help_heading = HELP_HEADING)]
pub(crate) renderer: Option<ClientRenderer>,

/// Build in release mode [default: false]
#[clap(long, short, help_heading = HELP_HEADING)]
Expand Down
156 changes: 116 additions & 40 deletions packages/cli/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,118 @@ use std::str::FromStr;
clap::ValueEnum,
)]
#[non_exhaustive]
pub(crate) enum Platform {
pub(crate) enum PlatformArg {
/// Targeting the web platform using WASM
#[clap(name = "web")]
#[serde(rename = "web")]
#[default]
Web,

/// Targeting macos desktop
/// When running on macos, you can also use `--platform desktop` to build for the desktop
#[cfg_attr(target_os = "macos", clap(alias = "desktop"))]
#[clap(name = "macos")]
#[serde(rename = "macos")]
MacOS,

/// Targeting windows desktop
/// When running on windows, you can also use `--platform desktop` to build for the desktop
#[cfg_attr(target_os = "windows", clap(alias = "desktop"))]
#[clap(name = "windows")]
#[serde(rename = "windows")]
Windows,

/// Targeting linux desktop
/// When running on linux, you can also use `--platform desktop` to build for the desktop
#[cfg_attr(target_os = "linux", clap(alias = "desktop"))]
#[clap(name = "linux")]
#[serde(rename = "linux")]
Linux,

/// Targeting the ios platform
///
/// Can't work properly if you're not building from an Apple device.
#[clap(name = "ios")]
#[serde(rename = "ios")]
Ios,

/// Targeting the android platform
#[clap(name = "android")]
#[serde(rename = "android")]
Android,

/// Targeting the current platform with the "desktop" renderer
#[clap(name = "desktop")]
Desktop,

/// Targeting the current platform with the "native" renderer
#[clap(name = "native")]
Native,

/// Targeting the server platform using Axum and Dioxus-Fullstack
///
/// This is implicitly passed if `fullstack` is enabled as a feature. Using this variant simply
/// means you're only building the server variant without the `.wasm` to serve.
#[clap(name = "server")]
#[serde(rename = "server")]
Server,

/// Targeting the static generation platform using SSR and Dioxus-Fullstack
#[clap(name = "liveview")]
Liveview,
}

#[derive(
Copy,
Clone,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Debug,
clap::ValueEnum,
)]
#[non_exhaustive]
pub(crate) enum ClientRenderer {
/// Targeting webview renderer
#[serde(rename = "webview")]
Webview,

/// Targeting native renderer
#[serde(rename = "native")]
Native,
}

#[derive(
Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug, Default,
)]
#[non_exhaustive]
pub(crate) enum Platform {
/// Targeting the web platform using WASM
#[serde(rename = "web")]
#[default]
Web,

/// Targeting macos desktop
#[serde(rename = "macos")]
MacOS,

/// Targeting windows desktop
#[serde(rename = "windows")]
Windows,

/// Targeting linux desktop
#[serde(rename = "linux")]
Linux,

/// Targeting the ios platform
///
/// Can't work properly if you're not building from an Apple device.
#[serde(rename = "ios")]
Ios,

/// Targeting the android platform
#[serde(rename = "android")]
Android,

/// Targeting the server platform using Axum and Dioxus-Fullstack
///
/// This is implicitly passed if `fullstack` is enabled as a feature. Using this variant simply
/// means you're only building the server variant without the `.wasm` to serve.
#[serde(rename = "server")]
Server,

/// Targeting the static generation platform using SSR and Dioxus-Fullstack
#[serde(rename = "liveview")]
Liveview,
}
Expand Down Expand Up @@ -113,18 +175,49 @@ impl Display for Platform {
}
}

impl From<PlatformArg> for Platform {
fn from(value: PlatformArg) -> Self {
match value {
// Most values map 1:1
PlatformArg::Web => Platform::Web,
PlatformArg::MacOS => Platform::MacOS,
PlatformArg::Windows => Platform::Windows,
PlatformArg::Linux => Platform::Linux,
PlatformArg::Ios => Platform::Ios,
PlatformArg::Android => Platform::Android,
PlatformArg::Server => Platform::Server,
PlatformArg::Liveview => Platform::Liveview,

// The alias arguments
PlatformArg::Desktop | PlatformArg::Native => Platform::TARGET_PLATFORM.unwrap(),
}
}
}

impl Platform {
/// Get the feature name for the platform in the dioxus crate
pub(crate) fn feature_name(&self) -> &str {
#[cfg(target_os = "macos")]
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Platform::MacOS);
#[cfg(target_os = "windows")]
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Platform::Windows);
#[cfg(target_os = "linux")]
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Platform::Linux);
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
pub(crate) const TARGET_PLATFORM: Option<Self> = None;

// /// Get the feature name for the platform in the dioxus crate
pub(crate) fn feature_name(&self, renderer: Option<ClientRenderer>) -> &str {
match self {
Platform::Web => "web",
Platform::MacOS => "desktop",
Platform::Windows => "desktop",
Platform::Linux => "desktop",
Platform::MacOS | Platform::Windows | Platform::Linux => match renderer {
None | Some(ClientRenderer::Webview) => "desktop",
Some(ClientRenderer::Native) => "native",
},
Platform::Ios | Platform::Android => match renderer {
None | Some(ClientRenderer::Webview) => "mobile",
Some(ClientRenderer::Native) => "native",
},
Platform::Server => "server",
Platform::Liveview => "liveview",
Platform::Ios => "mobile",
Platform::Android => "mobile",
}
}

Expand Down Expand Up @@ -160,25 +253,7 @@ impl Platform {
pub(crate) fn autodetect_from_cargo_feature(feature: &str) -> Option<Self> {
match feature {
"web" => Some(Platform::Web),
"desktop" | "native" => {
#[cfg(target_os = "macos")]
{
Some(Platform::MacOS)
}
#[cfg(target_os = "windows")]
{
Some(Platform::Windows)
}
#[cfg(target_os = "linux")]
{
Some(Platform::Linux)
}
// Possibly need a something for freebsd? Maybe default to Linux?
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
{
None
}
}
"desktop" | "native" => Platform::TARGET_PLATFORM,
"mobile" => None,
"liveview" => Some(Platform::Liveview),
"server" => Some(Platform::Server),
Expand All @@ -188,6 +263,7 @@ impl Platform {

pub(crate) fn profile_name(&self, release: bool) -> String {
let base_profile = match self {
// TODO: add native profile?
Platform::MacOS | Platform::Windows | Platform::Linux => "desktop",
Platform::Web => "web",
Platform::Ios => "ios",
Expand Down
Loading