fix platform unification (#4536)

* fix platform unification

* fix doc
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2025-08-12 01:31:45 -07:00
1 parent a8230d8ff0
commit a519fba7dc
2 files changed
+70 -75

No files matched your search

-8
View File
@@ -372,7 +372,6 @@ pub(crate) struct BuildRequest {
pub(crate) profile: String,
pub(crate) release: bool,
pub(crate) bundle: BundleFormat,
pub(crate) enabled_renderers: Vec<Renderer>,
pub(crate) triple: Triple,
pub(crate) device: bool,
pub(crate) package: String,
@@ -619,12 +618,6 @@ impl BuildRequest {
},
};
// Just grab the renderers from the enabled renderers and discard the feature names
let enabled_renderers = enabled_renderers
.into_iter()
.map(|(renderer, _)| renderer)
.collect::<Vec<_>>();
// We usually use the simulator unless --device is passed *or* a device is detected by probing.
// For now, though, since we don't have probing, it just defaults to false
// Tools like xcrun/adb can detect devices
@@ -808,7 +801,6 @@ impl BuildRequest {
device,
workspace,
config,
enabled_renderers,
target_dir,
custom_linker,
link_args_file,
+70 -67
View File
@@ -40,41 +40,77 @@ pub struct BuildTargets {
pub server: Option<BuildRequest>,
}
impl BuildArgs {
fn default_client(&self) -> &TargetArgs {
&self.build_arguments
}
fn default_server(&self, client: &BuildRequest) -> Option<&TargetArgs> {
// Now resolve the builds that we need to.
// These come from the args, but we'd like them to come from the `TargetCmd` chained object
//
// The process here is as follows:
//
// - Create the BuildRequest for the primary target
// - If that BuildRequest is "fullstack", then add the client features
// - If that BuildRequest is "fullstack", then also create a BuildRequest for the server
// with the server features
//
// This involves modifying the BuildRequest to add the client features and server features
// only if we can properly detect that it's a fullstack build. Careful with this, since
// we didn't build BuildRequest to be generally mutable.
let default_server = client.enabled_renderers.contains(&crate::Renderer::Server);
// Make sure we set the fullstack platform so we actually build the fullstack variant
// Users need to enable "fullstack" in their default feature set.
// todo(jon): fullstack *could* be a feature of the app, but right now we're assuming it's always enabled
//
// Now we need to resolve the client features
let fullstack = ((default_server || client.fullstack_feature_enabled())
|| self.fullstack.unwrap_or(false))
&& self.fullstack != Some(false);
fullstack.then_some(&self.build_arguments)
}
}
impl CommandWithPlatformOverrides<BuildArgs> {
/// We need to decompose the combined `BuildArgs` into the individual targets that we need to build.
///
/// Only in a few cases do we spin out an additional server binary:
/// - the fullstack feature is passed
/// - the fullstack flag is enabled
/// - the server flag is enabled
///
/// The buildtargets configuration comes in two flavors:
/// - implied via the `fullstack` feature
/// - explicit when using `@server and @client`
///
/// We use the client arguments to build the client target, and then make a few changes to make
/// the server target.
///
/// The `--fullstack` feature is basically the same as passing `--features fullstack`
///
/// Some examples:
/// ```shell, ignore
/// dx serve --target wasm32-unknown-unknown --fullstack # serves both client and server
/// dx serve --target wasm32-unknown-unknown --features fullstack # serves both client and server
/// dx serve --target wasm32-unknown-unknown # only serves the client
/// dx serve --target wasm32-unknown-unknown # servers both if `fullstack` is enabled on dioxus
/// dx serve @client --target wasm32-unknown-unknown # only serves the client
/// dx serve @client --target wasm32-unknown-unknown --fullstack # serves both client and server
/// ```
///
/// Currently it is not possible to serve the server without the client, but this could be added in the future.
pub async fn into_targets(self) -> Result<BuildTargets> {
let workspace = Workspace::current().await?;
// do some logging to ensure dx matches the dioxus version since we're not always API compatible
workspace.check_dioxus_version_against_cli();
// The client args are the `@client` arguments, or the shared build arguments if @client is not specified.
let client_args = &self.client.as_ref().unwrap_or(&self.shared).build_arguments;
// Create the client build request
let client = BuildRequest::new(client_args, None, workspace.clone()).await?;
// Create the server build request if needed
// This happens when 1) fullstack is enabled, 2)
let mut server = None;
if matches!(self.shared.fullstack, Some(true))
|| client.fullstack_feature_enabled()
|| self.server.is_some()
{
match self.server.as_ref() {
Some(server_args) => {
server = Some(
BuildRequest::new(
&server_args.build_arguments,
Some(client.main_target.clone()),
workspace.clone(),
)
.await?,
);
}
None => {
let mut args = self.shared.build_arguments.clone();
args.platform = Some(crate::Platform::Server);
args.renderer.renderer = Some(crate::Renderer::Server);
args.target = Some(target_lexicon::Triple::host());
server = Some(BuildRequest::new(&args, None, workspace.clone()).await?);
}
}
}
Ok(BuildTargets { client, server })
}
pub async fn build(self) -> Result<StructuredOutput> {
tracing::info!("Building project...");
@@ -105,37 +141,4 @@ impl CommandWithPlatformOverrides<BuildArgs> {
server: targets.server.map(|s| s.root_dir()),
})
}
pub async fn into_targets(self) -> Result<BuildTargets> {
let workspace = Workspace::current().await?;
// do some logging to ensure dx matches the dioxus version since we're not always API compatible
workspace.check_dioxus_version_against_cli();
let client_args = match &self.client {
Some(client) => &client.build_arguments,
None => self.shared.default_client(),
};
let client = BuildRequest::new(client_args, None, workspace.clone()).await?;
let server_args = match &self.server {
Some(server) => Some(&server.build_arguments),
None => self.shared.default_server(&client),
};
let mut server = None;
// If there is a server, make sure we output in the same directory as the client build so we use the server
// to serve the web client
if let Some(server_args) = server_args {
// Copy the main target from the client to the server
let main_target = client.main_target.clone();
let mut server_args = server_args.clone();
// The renderer in the server build is always set to Server
server_args.renderer.renderer = Some(crate::Renderer::Server);
server =
Some(BuildRequest::new(&server_args, Some(main_target), workspace.clone()).await?);
}
Ok(BuildTargets { client, server })
}
}