diff --git a/packages/cli/src/build/request.rs b/packages/cli/src/build/request.rs index 5900c1277e..ddc6286c3a 100644 --- a/packages/cli/src/build/request.rs +++ b/packages/cli/src/build/request.rs @@ -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, 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::>(); - // 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, diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 54ec7b8692..e86b3cbbad 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -40,41 +40,77 @@ pub struct BuildTargets { pub server: Option, } -impl BuildArgs { - fn default_client(&self) -> &TargetArgs { - &self.build_arguments - } +impl CommandWithPlatformOverrides { + /// 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 { + 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?); + } + } + } - 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) + Ok(BuildTargets { client, server }) } -} -impl CommandWithPlatformOverrides { pub async fn build(self) -> Result { tracing::info!("Building project..."); @@ -105,37 +141,4 @@ impl CommandWithPlatformOverrides { server: targets.server.map(|s| s.root_dir()), }) } - - pub async fn into_targets(self) -> Result { - 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 }) - } }