CLI: add --renderer argument (#4320)
* Add --renderer argument to the CLI Signed-off-by: Nico Burns <nico@nicoburns.com> * Make `--platform native` work Signed-off-by: Nico Burns <nico@nicoburns.com> * Emit `krates` error when cargo metadata fails * Reinstate default "desktop" feature for examples * Remove commented 'no platform specified' error Signed-off-by: Nico Burns <nico@nicoburns.com> * use the target tripple and bundle format as the source of truth for the build * resolve renderer and bundle format * add shorthand flags * add headings to the help for shorthands * resolve the renderer from the target triple if it isn't passed * make value after --fullstack optional * convert desktop -> mobile when targeting mobile webview * use the new shorthand flags in the playwright tests * fix clippy * merge fix * cleanup merge conflicts * fix clippy * remove nit * restore platform as a legacy argument * improve help message * vendor openssl on native, pin server_fn * print build errors as warnings * add --desktop arg compat * adjust cli headings * prefer self.is_wasm_or_wasi() --------- Signed-off-by: Nico Burns <nico@nicoburns.com> Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com> Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
28 files changed
+998
-549
No files matched your search
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
serve::WebServer, BuildArtifacts, BuildRequest, BuildStage, BuilderUpdate, Platform,
|
||||
serve::WebServer, BuildArtifacts, BuildRequest, BuildStage, BuilderUpdate, BundleFormat,
|
||||
ProgressRx, ProgressTx, Result, RustcArgs, StructuredOutput,
|
||||
};
|
||||
use anyhow::{bail, Context};
|
||||
@@ -16,6 +16,7 @@ use std::{
|
||||
process::Stdio,
|
||||
};
|
||||
use subsecond_types::JumpTable;
|
||||
use target_lexicon::Architecture;
|
||||
use tokio::{
|
||||
io::{AsyncBufReadExt, BufReader, Lines},
|
||||
process::{Child, ChildStderr, ChildStdout, Command},
|
||||
@@ -189,7 +190,7 @@ impl AppBuilder {
|
||||
match bundle {
|
||||
Ok(Ok(bundle)) => BuilderUpdate::BuildReady { bundle },
|
||||
Ok(Err(err)) => BuilderUpdate::BuildFailed { err },
|
||||
Err(err) => BuilderUpdate::BuildFailed { err: anyhow::anyhow!("Build panicked! {:#?}", err) },
|
||||
Err(err) => BuilderUpdate::BuildFailed { err: anyhow::anyhow!("Build panicked! {err:#?}") },
|
||||
}
|
||||
},
|
||||
Some(Ok(Some(msg))) = OptionFuture::from(self.stdout.as_mut().map(|f| f.next_line())) => {
|
||||
@@ -300,7 +301,13 @@ impl AppBuilder {
|
||||
// for all other platforms, we need to use the ASLR reference to know where to insert the patch.
|
||||
let aslr_reference = match self.aslr_reference {
|
||||
Some(val) => val,
|
||||
None if self.build.platform == Platform::Web => 0,
|
||||
None if matches!(
|
||||
self.build.triple.architecture,
|
||||
Architecture::Wasm32 | Architecture::Wasm64
|
||||
) =>
|
||||
{
|
||||
0
|
||||
}
|
||||
None => {
|
||||
tracing::warn!(
|
||||
"Ignoring hotpatch since there is no ASLR reference. Is the client connected?"
|
||||
@@ -542,18 +549,18 @@ impl AppBuilder {
|
||||
);
|
||||
|
||||
// We try to use stdin/stdout to communicate with the app
|
||||
match self.build.platform {
|
||||
match self.build.bundle {
|
||||
// Unfortunately web won't let us get a proc handle to it (to read its stdout/stderr) so instead
|
||||
// use use the websocket to communicate with it. I wish we could merge the concepts here,
|
||||
// like say, opening the socket as a subprocess, but alas, it's simpler to do that somewhere else.
|
||||
Platform::Web => {
|
||||
BundleFormat::Web => {
|
||||
// Only the first build we open the web app, after that the user knows it's running
|
||||
if open_browser {
|
||||
self.open_web(open_address.unwrap_or(devserver_ip));
|
||||
}
|
||||
}
|
||||
|
||||
Platform::Ios => {
|
||||
BundleFormat::Ios => {
|
||||
if self.build.device {
|
||||
self.codesign_ios().await?;
|
||||
self.open_ios_device().await?
|
||||
@@ -562,16 +569,15 @@ impl AppBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
Platform::Android => {
|
||||
BundleFormat::Android => {
|
||||
self.open_android_sim(false, devserver_ip, envs).await?;
|
||||
}
|
||||
|
||||
// These are all just basically running the main exe, but with slightly different resource dir paths
|
||||
Platform::Server
|
||||
| Platform::MacOS
|
||||
| Platform::Windows
|
||||
| Platform::Linux
|
||||
| Platform::Liveview => self.open_with_main_exe(envs, args)?,
|
||||
BundleFormat::Server
|
||||
| BundleFormat::MacOS
|
||||
| BundleFormat::Windows
|
||||
| BundleFormat::Linux => self.open_with_main_exe(envs, args)?,
|
||||
};
|
||||
|
||||
self.builds_opened += 1;
|
||||
@@ -661,7 +667,7 @@ impl AppBuilder {
|
||||
}
|
||||
|
||||
// If the emulator is android, we need to copy the asset to the device with `adb push asset /data/local/tmp/dx/assets/filename.ext`
|
||||
if self.build.platform == Platform::Android {
|
||||
if self.build.bundle == BundleFormat::Android {
|
||||
let bundled_name = PathBuf::from(bundled.bundled_path());
|
||||
_ = self.copy_file_to_android_tmp(&from, &bundled_name).await;
|
||||
}
|
||||
@@ -684,7 +690,7 @@ impl AppBuilder {
|
||||
let mut jump_table = crate::build::create_jump_table(&new, &triple, cache)?;
|
||||
|
||||
// If it's android, we need to copy the assets to the device and then change the location of the patch
|
||||
if self.build.platform == Platform::Android {
|
||||
if self.build.bundle == BundleFormat::Android {
|
||||
jump_table.lib = self
|
||||
.copy_file_to_android_tmp(&new, &(PathBuf::from(new.file_name().unwrap())))
|
||||
.await?;
|
||||
@@ -777,7 +783,7 @@ impl AppBuilder {
|
||||
}
|
||||
|
||||
// If the emulator is android, we need to copy the asset to the device with `adb push asset /data/local/tmp/dx/assets/filename.ext`
|
||||
if self.build.platform == Platform::Android {
|
||||
if self.build.bundle == BundleFormat::Android {
|
||||
_ = self
|
||||
.copy_file_to_android_tmp(&changed_file, &bundled_name)
|
||||
.await;
|
||||
@@ -972,7 +978,7 @@ impl AppBuilder {
|
||||
.await?;
|
||||
|
||||
if !output.status.success() {
|
||||
bail!("Failed to install app: {:?}", output);
|
||||
bail!("Failed to install app: {output:?}");
|
||||
}
|
||||
|
||||
let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?)
|
||||
@@ -1007,7 +1013,7 @@ impl AppBuilder {
|
||||
.await?;
|
||||
|
||||
if !output.status.success() {
|
||||
bail!("Failed to launch app: {:?}", output);
|
||||
bail!("Failed to launch app: {output:?}");
|
||||
}
|
||||
|
||||
let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?)
|
||||
@@ -1032,7 +1038,7 @@ impl AppBuilder {
|
||||
.await?;
|
||||
|
||||
if !output.status.success() {
|
||||
bail!("Failed to resume app: {:?}", output);
|
||||
bail!("Failed to resume app: {output:?}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -1255,8 +1261,8 @@ We checked the folders:
|
||||
let port = devserver_socket.port();
|
||||
if let Err(e) = Command::new(&adb)
|
||||
.arg("reverse")
|
||||
.arg(format!("tcp:{}", port))
|
||||
.arg(format!("tcp:{}", port))
|
||||
.arg(format!("tcp:{port}"))
|
||||
.arg(format!("tcp:{port}"))
|
||||
.output()
|
||||
.await
|
||||
{
|
||||
@@ -1362,18 +1368,14 @@ We checked the folders:
|
||||
let mut main_exe = self.build.main_exe();
|
||||
|
||||
// The requirement here is based on the platform, not necessarily our current architecture.
|
||||
let requires_entropy = match self.build.platform {
|
||||
let requires_entropy = match self.build.bundle {
|
||||
// When running "bundled", we don't need entropy
|
||||
Platform::Web => false,
|
||||
Platform::MacOS => false,
|
||||
Platform::Ios => false,
|
||||
Platform::Android => false,
|
||||
BundleFormat::Web | BundleFormat::MacOS | BundleFormat::Ios | BundleFormat::Android => {
|
||||
false
|
||||
}
|
||||
|
||||
// But on platforms that aren't running as "bundled", we do.
|
||||
Platform::Windows => true,
|
||||
Platform::Linux => true,
|
||||
Platform::Server => true,
|
||||
Platform::Liveview => true,
|
||||
BundleFormat::Windows | BundleFormat::Linux | BundleFormat::Server => true,
|
||||
};
|
||||
|
||||
if requires_entropy || crate::devcfg::should_force_entropy() {
|
||||
@@ -1443,24 +1445,22 @@ We checked the folders:
|
||||
}
|
||||
|
||||
pub(crate) async fn open_debugger(&mut self, server: &WebServer) -> Result<()> {
|
||||
let url = match self.build.platform {
|
||||
Platform::MacOS
|
||||
| Platform::Windows
|
||||
| Platform::Linux
|
||||
| Platform::Server
|
||||
| Platform::Liveview => {
|
||||
let url = match self.build.bundle {
|
||||
BundleFormat::MacOS
|
||||
| BundleFormat::Windows
|
||||
| BundleFormat::Linux
|
||||
| BundleFormat::Server => {
|
||||
let Some(Some(pid)) = self.child.as_mut().map(|f| f.id()) else {
|
||||
tracing::warn!("No process to attach debugger to");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
format!(
|
||||
"vscode://vadimcn.vscode-lldb/launch/config?{{'request':'attach','pid':{}}}",
|
||||
pid
|
||||
"vscode://vadimcn.vscode-lldb/launch/config?{{'request':'attach','pid':{pid}}}"
|
||||
)
|
||||
}
|
||||
|
||||
Platform::Web => {
|
||||
BundleFormat::Web => {
|
||||
// code --open-url "vscode://DioxusLabs.dioxus/debugger?uri=http://127.0.0.1:8080"
|
||||
// todo - debugger could open to the *current* page afaik we don't have a way to have that info
|
||||
let address = server.devserver_address();
|
||||
@@ -1474,7 +1474,7 @@ We checked the folders:
|
||||
format!("vscode://DioxusLabs.dioxus/debugger?uri={protocol}://{address}{base_path}")
|
||||
}
|
||||
|
||||
Platform::Ios => {
|
||||
BundleFormat::Ios => {
|
||||
let Some(pid) = self.pid else {
|
||||
tracing::warn!("No process to attach debugger to");
|
||||
return Ok(());
|
||||
@@ -1513,7 +1513,7 @@ We checked the folders:
|
||||
// (lldb) settings append target.exec-search-paths target/dx/tw6/debug/android/app/app/src/main/jniLibs/arm64-v8a/libdioxusmain.so
|
||||
// (lldb) process handle SIGSEGV --pass true --stop false --notify true (otherwise the java threads cause crash)
|
||||
//
|
||||
Platform::Android => {
|
||||
BundleFormat::Android => {
|
||||
// adb push ./sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/lib/clang/20/lib/linux/aarch64/lldb-server /tmp
|
||||
// adb shell "/tmp/lldb-server --server --listen ..."
|
||||
// "vscode://vadimcn.vscode-lldb/launch/config?{{'request':'connect','port': {}}}",
|
||||
@@ -1601,7 +1601,7 @@ We checked the folders:
|
||||
}
|
||||
};
|
||||
|
||||
tracing::info!("Opening debugger for [{}]: {url}", self.build.platform);
|
||||
tracing::info!("Opening debugger for [{}]: {url}", self.build.bundle);
|
||||
|
||||
_ = tokio::process::Command::new("code")
|
||||
.arg("--open-url")
|
||||
|
||||
@@ -105,7 +105,7 @@ impl BuildContext {
|
||||
}
|
||||
|
||||
pub(crate) fn status_build_error(&self, line: String) {
|
||||
tracing::debug!(dx_src = ?TraceSrc::Cargo, "{line}");
|
||||
tracing::warn!(dx_src = ?TraceSrc::Cargo, "{line}");
|
||||
}
|
||||
|
||||
pub(crate) fn status_build_message(&self, line: String) {
|
||||
|
||||
@@ -775,7 +775,7 @@ pub fn create_undefined_symbol_stub(
|
||||
let mut defined_symbols = HashSet::new();
|
||||
|
||||
for path in sorted {
|
||||
let bytes = std::fs::read(path).with_context(|| format!("failed to read {:?}", path))?;
|
||||
let bytes = std::fs::read(path).with_context(|| format!("failed to read {path:?}"))?;
|
||||
let file = File::parse(bytes.deref() as &[u8])?;
|
||||
for symbol in file.symbols() {
|
||||
if symbol.is_undefined() {
|
||||
@@ -853,7 +853,7 @@ pub fn create_undefined_symbol_stub(
|
||||
if aslr_reference < aslr_ref_address {
|
||||
return Err(PatchError::InvalidModule(
|
||||
format!(
|
||||
"ASLR reference is less than the main module's address - is there a `main`?. {:x} < {:x}", aslr_reference, aslr_ref_address )
|
||||
"ASLR reference is less than the main module's address - is there a `main`?. {aslr_reference:x} < {aslr_ref_address:x}" )
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
+274
-212
File diff suppressed because it is too large.
Load diff
@@ -108,11 +108,11 @@ fn refactor_file(
|
||||
let out = dioxus_autofmt::apply_formats(&s, edits);
|
||||
|
||||
if file == "-" {
|
||||
print!("{}", out);
|
||||
print!("{out}");
|
||||
} else if let Err(e) = fs::write(&file, out) {
|
||||
tracing::error!("failed to write formatted content to file: {e}",);
|
||||
} else {
|
||||
println!("formatted {}", file);
|
||||
println!("formatted {file}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -191,7 +191,7 @@ fn autoformat_project(
|
||||
let files_formatted: usize = counts.into_iter().flatten().sum();
|
||||
|
||||
if files_formatted > 0 && check {
|
||||
bail!("{} files needed formatting", files_formatted);
|
||||
bail!("{files_formatted} files needed formatting");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -252,7 +252,7 @@ fn format_syn_error(err: syn::Error) -> Error {
|
||||
let start = err.span().start();
|
||||
let line = start.line;
|
||||
let column = start.column;
|
||||
anyhow::anyhow!("Syntax Error in line {} column {}:\n{}", line, column, err)
|
||||
anyhow::anyhow!("Syntax Error in line {line} column {column}:\n{err}")
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::BuildMode;
|
||||
use crate::{cli::*, AppBuilder, BuildRequest, Workspace};
|
||||
use crate::{BuildMode, Platform};
|
||||
|
||||
use super::target::TargetArgs;
|
||||
|
||||
@@ -12,7 +12,11 @@ pub struct BuildArgs {
|
||||
/// Enable fullstack mode [default: false]
|
||||
///
|
||||
/// This is automatically detected from `dx serve` if the "fullstack" feature is enabled by default.
|
||||
#[clap(long)]
|
||||
#[arg(
|
||||
long,
|
||||
default_missing_value = "true",
|
||||
num_args = 0..=1,
|
||||
)]
|
||||
pub(crate) fullstack: Option<bool>,
|
||||
|
||||
/// Pre-render all routes returned from the app's `/static_routes` endpoint [default: false]
|
||||
@@ -48,7 +52,7 @@ impl BuildArgs {
|
||||
// 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_platforms.contains(&Platform::Server);
|
||||
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.
|
||||
@@ -119,8 +123,8 @@ impl CommandWithPlatformOverrides<BuildArgs> {
|
||||
// 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 platform in the server build is always set to Server
|
||||
server_args.platform = Some(Platform::Server);
|
||||
// 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?);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{AppBuilder, BuildArgs, BuildMode, BuildRequest, Platform};
|
||||
use crate::{AppBuilder, BuildArgs, BuildMode, BuildRequest, BundleFormat};
|
||||
use anyhow::{bail, Context};
|
||||
use path_absolutize::Absolutize;
|
||||
use std::collections::HashMap;
|
||||
@@ -55,7 +55,7 @@ impl Bundle {
|
||||
}
|
||||
|
||||
// If we're building for iOS, we need to bundle the iOS bundle
|
||||
if client.platform == Platform::Ios && self.package_types.is_none() {
|
||||
if client.bundle == BundleFormat::Ios && self.package_types.is_none() {
|
||||
self.package_types = Some(vec![crate::PackageType::IosBundle]);
|
||||
}
|
||||
|
||||
@@ -67,9 +67,9 @@ impl Bundle {
|
||||
}
|
||||
|
||||
// Create a list of bundles that we might need to copy
|
||||
match client.platform {
|
||||
match client.bundle {
|
||||
// By default, mac/win/linux work with tauri bundle
|
||||
Platform::MacOS | Platform::Linux | Platform::Windows => {
|
||||
BundleFormat::MacOS | BundleFormat::Linux | BundleFormat::Windows => {
|
||||
tracing::info!("Running desktop bundler...");
|
||||
for bundle in Self::bundle_desktop(&client, &self.package_types)? {
|
||||
bundles.extend(bundle.bundle_paths);
|
||||
@@ -77,15 +77,14 @@ impl Bundle {
|
||||
}
|
||||
|
||||
// Web/ios can just use their root_dir
|
||||
Platform::Web => bundles.push(client.root_dir()),
|
||||
Platform::Ios => {
|
||||
BundleFormat::Web => bundles.push(client.root_dir()),
|
||||
BundleFormat::Ios => {
|
||||
tracing::warn!("iOS bundles are not currently codesigned! You will need to codesign the app before distributing.");
|
||||
bundles.push(client.root_dir())
|
||||
}
|
||||
Platform::Server => bundles.push(client.root_dir()),
|
||||
Platform::Liveview => bundles.push(client.root_dir()),
|
||||
BundleFormat::Server => bundles.push(client.root_dir()),
|
||||
|
||||
Platform::Android => {
|
||||
BundleFormat::Android => {
|
||||
let aab = client
|
||||
.android_gradle_bundle()
|
||||
.await
|
||||
@@ -145,16 +144,16 @@ impl Bundle {
|
||||
let krate = &build;
|
||||
let exe = build.main_exe();
|
||||
|
||||
_ = std::fs::remove_dir_all(krate.bundle_dir(build.platform));
|
||||
_ = std::fs::remove_dir_all(krate.bundle_dir(build.bundle));
|
||||
|
||||
let package = krate.package();
|
||||
let mut name: PathBuf = krate.executable_name().into();
|
||||
if cfg!(windows) {
|
||||
name.set_extension("exe");
|
||||
}
|
||||
std::fs::create_dir_all(krate.bundle_dir(build.platform))
|
||||
std::fs::create_dir_all(krate.bundle_dir(build.bundle))
|
||||
.context("Failed to create bundle directory")?;
|
||||
std::fs::copy(&exe, krate.bundle_dir(build.platform).join(&name))
|
||||
std::fs::copy(&exe, krate.bundle_dir(build.bundle).join(&name))
|
||||
.with_context(|| "Failed to copy the output executable into the bundle directory")?;
|
||||
|
||||
let binaries = vec![
|
||||
@@ -223,7 +222,7 @@ impl Bundle {
|
||||
}
|
||||
|
||||
let mut settings = SettingsBuilder::new()
|
||||
.project_out_directory(krate.bundle_dir(build.platform))
|
||||
.project_out_directory(krate.bundle_dir(build.bundle))
|
||||
.package_settings(PackageSettings {
|
||||
product_name: krate.bundled_app_name(),
|
||||
version: package.version.to_string(),
|
||||
|
||||
@@ -119,7 +119,7 @@ async fn check_files_and_report(files_to_check: Vec<PathBuf>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
1 => Err(anyhow!("1 issue found.")),
|
||||
_ => Err(anyhow!("{} issues found.", total_issues)),
|
||||
_ => Err(anyhow!("{total_issues} issues found.")),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-20
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
serve::{AppServer, ServeUpdate, WebServer},
|
||||
BuilderUpdate, Platform, Result,
|
||||
BuilderUpdate, BundleFormat, Result,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use dioxus_dx_wire_format::BuildStage;
|
||||
@@ -43,7 +43,7 @@ impl RunArgs {
|
||||
|
||||
match msg {
|
||||
ServeUpdate::BuilderUpdate { id, update } => {
|
||||
let platform = builder.get_build(id).unwrap().build.platform;
|
||||
let bundle_format = builder.get_build(id).unwrap().build.bundle;
|
||||
|
||||
// And then update the websocketed clients with the new build status in case they want it
|
||||
devserver.new_build_update(&update).await;
|
||||
@@ -59,7 +59,7 @@ impl RunArgs {
|
||||
.await
|
||||
.inspect_err(|e| tracing::error!("Failed to open app: {}", e));
|
||||
|
||||
if platform == Platform::Web {
|
||||
if bundle_format == BundleFormat::Web {
|
||||
tracing::info!(
|
||||
"Serving app at http://{}:{}",
|
||||
builder.devserver_bind_ip,
|
||||
@@ -69,7 +69,7 @@ impl RunArgs {
|
||||
}
|
||||
BuilderUpdate::Progress { stage } => match stage {
|
||||
BuildStage::Initializing => {
|
||||
tracing::info!("[{platform}] Initializing build")
|
||||
tracing::info!("[{bundle_format}] Initializing build")
|
||||
}
|
||||
BuildStage::Starting { .. } => {}
|
||||
BuildStage::InstallingTooling => {}
|
||||
@@ -79,15 +79,15 @@ impl RunArgs {
|
||||
krate,
|
||||
} => {
|
||||
tracing::debug!(
|
||||
"[{platform}] ({current}/{total}) Compiling {krate} ",
|
||||
"[{bundle_format}] ({current}/{total}) Compiling {krate} ",
|
||||
)
|
||||
}
|
||||
BuildStage::RunningBindgen => {
|
||||
tracing::info!("[{platform}] Running WASM bindgen")
|
||||
tracing::info!("[{bundle_format}] Running WASM bindgen")
|
||||
}
|
||||
BuildStage::SplittingBundle => {}
|
||||
BuildStage::OptimizingWasm => {
|
||||
tracing::info!("[{platform}] Optimizing WASM with `wasm-opt`")
|
||||
tracing::info!("[{bundle_format}] Optimizing WASM with `wasm-opt`")
|
||||
}
|
||||
BuildStage::Linking => tracing::info!("Linking app"),
|
||||
BuildStage::Hotpatching => {}
|
||||
@@ -96,49 +96,51 @@ impl RunArgs {
|
||||
total,
|
||||
path,
|
||||
} => tracing::info!(
|
||||
"[{platform}] Copying asset {} ({current}/{total})",
|
||||
"[{bundle_format}] Copying asset {} ({current}/{total})",
|
||||
path.display(),
|
||||
),
|
||||
BuildStage::Bundling => tracing::info!("[{platform}] Bundling app"),
|
||||
BuildStage::Bundling => {
|
||||
tracing::info!("[{bundle_format}] Bundling app")
|
||||
}
|
||||
BuildStage::RunningGradle => {
|
||||
tracing::info!("[{platform}] Running Gradle")
|
||||
tracing::info!("[{bundle_format}] Running Gradle")
|
||||
}
|
||||
BuildStage::Success => {}
|
||||
BuildStage::Restarting => {}
|
||||
BuildStage::CompressingAssets => {}
|
||||
BuildStage::ExtractingAssets => {}
|
||||
BuildStage::Prerendering => {
|
||||
tracing::info!("[{platform}] Prerendering app")
|
||||
tracing::info!("[{bundle_format}] Prerendering app")
|
||||
}
|
||||
BuildStage::Failed => {
|
||||
tracing::error!("[{platform}] Build failed");
|
||||
bail!("Build failed for platform: {platform}");
|
||||
tracing::error!("[{bundle_format}] Build failed");
|
||||
bail!("Build failed for platform: {bundle_format}");
|
||||
}
|
||||
BuildStage::Aborted => {
|
||||
tracing::error!("[{platform}] Build aborted");
|
||||
bail!("Build aborted for platform: {platform}");
|
||||
tracing::error!("[{bundle_format}] Build aborted");
|
||||
bail!("Build aborted for platform: {bundle_format}");
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
BuilderUpdate::CompilerMessage { message } => {
|
||||
print!("{}", message);
|
||||
print!("{message}");
|
||||
}
|
||||
BuilderUpdate::BuildFailed { err } => {
|
||||
tracing::error!("❌ Build failed: {}", err);
|
||||
return Err(err);
|
||||
}
|
||||
BuilderUpdate::StdoutReceived { msg } => {
|
||||
tracing::info!("[{platform}] {msg}");
|
||||
tracing::info!("[{bundle_format}] {msg}");
|
||||
}
|
||||
BuilderUpdate::StderrReceived { msg } => {
|
||||
tracing::error!("[{platform}] {msg}");
|
||||
tracing::error!("[{bundle_format}] {msg}");
|
||||
}
|
||||
BuilderUpdate::ProcessExited { status } => {
|
||||
if !status.success() {
|
||||
tracing::error!(
|
||||
"Application [{platform}] exited with error: {status}"
|
||||
"Application [{bundle_format}] exited with error: {status}"
|
||||
);
|
||||
bail!("Application [{platform}] exited with error: {status}");
|
||||
bail!("Application [{bundle_format}] exited with error: {status}");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -6,15 +6,15 @@ use std::{backtrace::Backtrace, panic::AssertUnwindSafe};
|
||||
|
||||
/// Serve the project
|
||||
///
|
||||
/// `dx serve` takes cargo args by default, except with a required `--platform` arg:
|
||||
/// `dx serve` takes cargo args by default with additional renderer args like `--web`, `--webview`, and `--native`:
|
||||
///
|
||||
/// ```sh
|
||||
/// dx serve --example blah --target blah --platform android
|
||||
/// dx serve --example blah --target blah --android
|
||||
/// ```
|
||||
///
|
||||
/// A simple serve:
|
||||
/// ```sh
|
||||
/// dx serve --platform web
|
||||
/// dx serve --web
|
||||
/// ```
|
||||
///
|
||||
/// As of dioxus 0.7, `dx serve` allows independent customization of the client and server builds,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::cli::*;
|
||||
use crate::BundleFormat;
|
||||
use crate::Platform;
|
||||
use crate::RendererArg;
|
||||
use crate::TargetAlias;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
const HELP_HEADING: &str = "Target Options";
|
||||
@@ -7,7 +10,25 @@ const HELP_HEADING: &str = "Target Options";
|
||||
/// A single target to build for
|
||||
#[derive(Clone, Debug, Default, Deserialize, Parser)]
|
||||
pub(crate) struct TargetArgs {
|
||||
/// Build platform: support Web & Desktop [default: "default_platform"]
|
||||
/// The target alias to use for this build. Supports wasm, macos, windows, linux, ios, android, and host [default: "host"]
|
||||
#[clap(flatten)]
|
||||
pub(crate) target_alias: TargetAlias,
|
||||
|
||||
/// Build renderer: supports web, webview, native, server, and liveview
|
||||
#[clap(flatten)]
|
||||
pub(crate) renderer: RendererArg,
|
||||
|
||||
/// The bundle format to target for the build: supports web, macos, windows, linux, ios, android, and server
|
||||
#[clap(long, value_enum, help_heading = HELP_HEADING)]
|
||||
pub(crate) bundle: Option<BundleFormat>,
|
||||
|
||||
/// Build platform: supports Web, MacOS, Windows, Linux, iOS, Android, and Server
|
||||
///
|
||||
/// The platform implies a combination of the target alias, renderer, and bundle format flags.
|
||||
///
|
||||
/// You should generally prefer to use the `--web`, `--webview`, or `--native` flags to set the renderer
|
||||
/// or the `--wasm`, `--macos`, `--windows`, `--linux`, `--ios`, or `--android` flags to set the target alias
|
||||
/// instead of this flag. The renderer, target alias, and bundle format will be inferred if you only pass one.
|
||||
#[clap(long, value_enum, help_heading = HELP_HEADING)]
|
||||
pub(crate) platform: Option<Platform>,
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ impl Translate {
|
||||
// instead we should be printing as json (or maybe even a different format) if we're not interactive
|
||||
match self.output {
|
||||
Some(output) => std::fs::write(output, &html)?,
|
||||
None => print!("{}", html),
|
||||
None => print!("{html}"),
|
||||
}
|
||||
|
||||
Ok(StructuredOutput::HtmlTranslate { html })
|
||||
|
||||
@@ -341,7 +341,7 @@ impl FromStr for PackageType {
|
||||
"appimage" => Ok(PackageType::AppImage),
|
||||
"dmg" => Ok(PackageType::Dmg),
|
||||
"updater" => Ok(PackageType::Updater),
|
||||
_ => Err(format!("{} is not a valid package type", s)),
|
||||
_ => Err(format!("{s} is not a valid package type")),
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-21
@@ -14,10 +14,12 @@
|
||||
//! 3. Build CLI layer for routing tracing logs to the TUI.
|
||||
//! 4. Build fmt layer for non-interactive logging with a custom writer that prevents output during interactive mode.
|
||||
|
||||
use crate::{serve::ServeUpdate, Cli, Commands, Platform as TargetPlatform, Verbosity};
|
||||
use crate::BundleFormat;
|
||||
use crate::{serve::ServeUpdate, Cli, Commands, Verbosity};
|
||||
use cargo_metadata::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use clap::Parser;
|
||||
use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
|
||||
use std::str::FromStr;
|
||||
use std::sync::OnceLock;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@@ -315,7 +317,7 @@ impl Visit for CollectVisitor {
|
||||
let name = field.name();
|
||||
|
||||
let mut value_string = String::new();
|
||||
write!(value_string, "{:?}", value).unwrap();
|
||||
write!(value_string, "{value:?}").unwrap();
|
||||
|
||||
if name == "message" {
|
||||
self.message = value_string;
|
||||
@@ -335,8 +337,8 @@ impl Visit for CollectVisitor {
|
||||
fn format_field(field_name: &str, value: &dyn Debug) -> String {
|
||||
let mut out = String::new();
|
||||
match field_name {
|
||||
"message" => write!(out, "{:?}", value),
|
||||
_ => write!(out, "{}={:?}", field_name, value),
|
||||
"message" => write!(out, "{value:?}"),
|
||||
_ => write!(out, "{field_name}={value:?}"),
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
@@ -391,7 +393,7 @@ impl TraceMsg {
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum TraceSrc {
|
||||
App(TargetPlatform),
|
||||
App(BundleFormat),
|
||||
Dev,
|
||||
Build,
|
||||
Bundle,
|
||||
@@ -412,12 +414,9 @@ impl From<String> for TraceSrc {
|
||||
"dev" => Self::Dev,
|
||||
"bld" => Self::Build,
|
||||
"cargo" => Self::Cargo,
|
||||
"app" => Self::App(TargetPlatform::Web),
|
||||
"windows" => Self::App(TargetPlatform::Windows),
|
||||
"macos" => Self::App(TargetPlatform::MacOS),
|
||||
"linux" => Self::App(TargetPlatform::Linux),
|
||||
"server" => Self::App(TargetPlatform::Server),
|
||||
_ => Self::Unknown,
|
||||
other => BundleFormat::from_str(other)
|
||||
.map(Self::App)
|
||||
.unwrap_or_else(|_| Self::Unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,16 +424,7 @@ impl From<String> for TraceSrc {
|
||||
impl Display for TraceSrc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::App(platform) => match platform {
|
||||
TargetPlatform::Web => write!(f, "web"),
|
||||
TargetPlatform::MacOS => write!(f, "macos"),
|
||||
TargetPlatform::Windows => write!(f, "windows"),
|
||||
TargetPlatform::Linux => write!(f, "linux"),
|
||||
TargetPlatform::Server => write!(f, "server"),
|
||||
TargetPlatform::Ios => write!(f, "ios"),
|
||||
TargetPlatform::Android => write!(f, "android"),
|
||||
TargetPlatform::Liveview => write!(f, "liveview"),
|
||||
},
|
||||
Self::App(bundle) => write!(f, "{bundle}"),
|
||||
Self::Dev => write!(f, "dev"),
|
||||
Self::Build => write!(f, "build"),
|
||||
Self::Cargo => write!(f, "cargo"),
|
||||
|
||||
+507
-143
@@ -1,6 +1,484 @@
|
||||
use anyhow::{Context, Result};
|
||||
use clap::{arg, ArgMatches, Args, FromArgMatches};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use target_lexicon::{Architecture, Environment, OperatingSystem, Triple};
|
||||
|
||||
use crate::Workspace;
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug, Default,
|
||||
)]
|
||||
#[non_exhaustive]
|
||||
pub(crate) enum TargetAlias {
|
||||
/// Targeting the WASM architecture
|
||||
Wasm,
|
||||
|
||||
/// Targeting macos desktop
|
||||
MacOS,
|
||||
|
||||
/// Targeting windows desktop
|
||||
Windows,
|
||||
|
||||
/// Targeting linux desktop
|
||||
Linux,
|
||||
|
||||
/// Targeting the ios platform
|
||||
///
|
||||
/// Can't work properly if you're not building from an Apple device.
|
||||
Ios,
|
||||
|
||||
/// Targeting the android platform
|
||||
Android,
|
||||
|
||||
/// Targeting the current target
|
||||
Host,
|
||||
|
||||
/// An unknown target platform
|
||||
#[default]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Args for TargetAlias {
|
||||
fn augment_args(cmd: clap::Command) -> clap::Command {
|
||||
const HELP_HEADING: &str = "Target Alias";
|
||||
cmd.arg(arg!(--wasm "Target the wasm triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--macos "Target the macos triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--windows "Target the windows triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--linux "Target the linux triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--ios "Target the ios triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--android "Target the android triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--host "Target the host triple").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--desktop "Target the host triple").help_heading(HELP_HEADING))
|
||||
.group(
|
||||
clap::ArgGroup::new("target_alias")
|
||||
.args([
|
||||
"wasm", "macos", "windows", "linux", "ios", "android", "host", "host",
|
||||
])
|
||||
.multiple(false)
|
||||
.required(false),
|
||||
)
|
||||
}
|
||||
|
||||
fn augment_args_for_update(cmd: clap::Command) -> clap::Command {
|
||||
Self::augment_args(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgMatches for TargetAlias {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, clap::Error> {
|
||||
if let Some(platform) = matches.get_one::<clap::Id>("target_alias") {
|
||||
match platform.as_str() {
|
||||
"wasm" => Ok(Self::Wasm),
|
||||
"macos" => Ok(Self::MacOS),
|
||||
"windows" => Ok(Self::Windows),
|
||||
"linux" => Ok(Self::Linux),
|
||||
"ios" => Ok(Self::Ios),
|
||||
"android" => Ok(Self::Android),
|
||||
"host" => Ok(Self::Host),
|
||||
_ => Err(clap::Error::raw(
|
||||
clap::error::ErrorKind::InvalidValue,
|
||||
format!("Unknown target alias: {platform}"),
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(Self::Unknown)
|
||||
}
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), clap::Error> {
|
||||
*self = Self::from_arg_matches(matches)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetAlias {
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Self::MacOS);
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Self::Windows);
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Self::Linux);
|
||||
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = None;
|
||||
|
||||
pub(crate) async fn into_target(self, device: bool, workspace: &Workspace) -> Result<Triple> {
|
||||
match self {
|
||||
// Generally just use the host's triple for native executables unless specified otherwise
|
||||
Self::MacOS | Self::Windows | Self::Linux | Self::Host | Self::Unknown => {
|
||||
Ok(Triple::host())
|
||||
}
|
||||
|
||||
// We currently assume unknown-unknown for web, but we might want to eventually
|
||||
// support emscripten
|
||||
Self::Wasm => Ok("wasm32-unknown-unknown".parse()?),
|
||||
|
||||
// For iOS we should prefer the actual architecture for the simulator, but in lieu of actually
|
||||
// figuring that out, we'll assume aarch64 on m-series and x86_64 otherwise
|
||||
Self::Ios => {
|
||||
// use the host's architecture and sim if --device is passed
|
||||
use target_lexicon::{Architecture, HOST};
|
||||
let triple_str = match HOST.architecture {
|
||||
Architecture::Aarch64(_) if device => "aarch64-apple-ios",
|
||||
Architecture::Aarch64(_) => "aarch64-apple-ios-sim",
|
||||
_ if device => "x86_64-apple-ios",
|
||||
_ => "x86_64-apple-ios",
|
||||
};
|
||||
Ok(triple_str.parse()?)
|
||||
}
|
||||
|
||||
// Same idea with android but we figure out the connected device using adb
|
||||
Self::Android => Ok(workspace
|
||||
.android_tools()?
|
||||
.autodetect_android_device_triple()
|
||||
.await),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn or(self, other: Self) -> Self {
|
||||
if self == Self::Unknown {
|
||||
other
|
||||
} else {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug, Default,
|
||||
)]
|
||||
pub(crate) struct RendererArg {
|
||||
pub(crate) renderer: Option<Renderer>,
|
||||
}
|
||||
|
||||
impl Args for RendererArg {
|
||||
fn augment_args(cmd: clap::Command) -> clap::Command {
|
||||
const HELP_HEADING: &str = "Renderer";
|
||||
cmd.arg(arg!(--web "Enable the dioxus web renderer").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--webview "Enable the dioxus webview renderer").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--native "Enable the dioxus native renderer").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--server "Enable the dioxus server renderer").help_heading(HELP_HEADING))
|
||||
.arg(arg!(--liveview "Enable the dioxus liveview renderer").help_heading(HELP_HEADING))
|
||||
.group(
|
||||
clap::ArgGroup::new("renderer")
|
||||
.args(["web", "webview", "native", "server", "liveview"])
|
||||
.multiple(false)
|
||||
.required(false),
|
||||
)
|
||||
}
|
||||
|
||||
fn augment_args_for_update(cmd: clap::Command) -> clap::Command {
|
||||
Self::augment_args(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArgMatches for RendererArg {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, clap::Error> {
|
||||
if let Some(renderer) = matches.get_one::<clap::Id>("renderer") {
|
||||
match renderer.as_str() {
|
||||
"web" => Ok(Self {
|
||||
renderer: Some(Renderer::Web),
|
||||
}),
|
||||
"webview" => Ok(Self {
|
||||
renderer: Some(Renderer::Webview),
|
||||
}),
|
||||
"native" => Ok(Self {
|
||||
renderer: Some(Renderer::Native),
|
||||
}),
|
||||
"server" => Ok(Self {
|
||||
renderer: Some(Renderer::Server),
|
||||
}),
|
||||
"liveview" => Ok(Self {
|
||||
renderer: Some(Renderer::Liveview),
|
||||
}),
|
||||
_ => Err(clap::Error::raw(
|
||||
clap::error::ErrorKind::InvalidValue,
|
||||
format!("Unknown platform: {renderer}"),
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
Ok(Self { renderer: None })
|
||||
}
|
||||
}
|
||||
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), clap::Error> {
|
||||
*self = Self::from_arg_matches(matches)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RendererArg> for Option<Renderer> {
|
||||
fn from(val: RendererArg) -> Self {
|
||||
val.renderer
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub(crate) enum Renderer {
|
||||
/// Targeting webview renderer
|
||||
Webview,
|
||||
|
||||
/// Targeting native renderer
|
||||
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.
|
||||
Server,
|
||||
|
||||
/// Targeting the static generation platform using SSR and Dioxus-Fullstack
|
||||
Liveview,
|
||||
|
||||
/// Targeting the web renderer
|
||||
Web,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
/// Get the feature name for the platform in the dioxus crate
|
||||
pub(crate) fn feature_name(&self, target: &Triple) -> &str {
|
||||
match self {
|
||||
Renderer::Webview => match (target.environment, target.operating_system) {
|
||||
(Environment::Android, _) | (_, OperatingSystem::IOS(_)) => "mobile",
|
||||
_ => "desktop",
|
||||
},
|
||||
Renderer::Native => "native",
|
||||
Renderer::Server => "server",
|
||||
Renderer::Liveview => "liveview",
|
||||
Renderer::Web => "web",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn autodetect_from_cargo_feature(feature: &str) -> Option<Self> {
|
||||
match feature {
|
||||
"web" => Some(Self::Web),
|
||||
"desktop" | "mobile" => Some(Self::Webview),
|
||||
"native" => Some(Self::Native),
|
||||
"liveview" => Some(Self::Liveview),
|
||||
"server" => Some(Self::Server),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_platform(&self) -> TargetAlias {
|
||||
match self {
|
||||
Renderer::Webview | Renderer::Native | Renderer::Server | Renderer::Liveview => {
|
||||
TargetAlias::TARGET_PLATFORM.unwrap()
|
||||
}
|
||||
Renderer::Web => TargetAlias::Wasm,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_target(triple: &Triple) -> Self {
|
||||
match triple.architecture {
|
||||
// Assume any wasm32 or wasm64 target is a web target
|
||||
Architecture::Wasm32 | Architecture::Wasm64 => Self::Web,
|
||||
// Otherwise, assume webview for native targets
|
||||
_ => Self::Webview,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UnknownRendererError;
|
||||
|
||||
impl std::error::Error for UnknownRendererError {}
|
||||
|
||||
impl std::fmt::Display for UnknownRendererError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Unknown renderer")
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Renderer {
|
||||
type Err = UnknownRendererError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"webview" => Ok(Self::Webview),
|
||||
"native" => Ok(Self::Native),
|
||||
"server" => Ok(Self::Server),
|
||||
"liveview" => Ok(Self::Liveview),
|
||||
"web" => Ok(Self::Web),
|
||||
_ => Err(UnknownRendererError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Renderer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Renderer::Webview => "webview",
|
||||
Renderer::Native => "native",
|
||||
Renderer::Server => "server",
|
||||
Renderer::Liveview => "liveview",
|
||||
Renderer::Web => "web",
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(
|
||||
Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug, Default,
|
||||
)]
|
||||
#[non_exhaustive]
|
||||
pub(crate) enum BundleFormat {
|
||||
/// Targeting the web bundle structure
|
||||
#[serde(rename = "web")]
|
||||
#[default]
|
||||
Web,
|
||||
|
||||
/// Targeting the macos desktop bundle structure
|
||||
#[cfg_attr(target_os = "macos", serde(alias = "desktop"))]
|
||||
#[serde(rename = "macos")]
|
||||
MacOS,
|
||||
|
||||
/// Targeting the windows desktop bundle structure
|
||||
#[cfg_attr(target_os = "windows", serde(alias = "desktop"))]
|
||||
#[serde(rename = "windows")]
|
||||
Windows,
|
||||
|
||||
/// Targeting the linux desktop bundle structure
|
||||
#[cfg_attr(target_os = "linux", serde(alias = "desktop"))]
|
||||
#[serde(rename = "linux")]
|
||||
Linux,
|
||||
|
||||
/// Targeting the server bundle structure (a single binary placed next to the web build)
|
||||
#[serde(rename = "server")]
|
||||
Server,
|
||||
|
||||
/// Targeting the ios bundle structure
|
||||
///
|
||||
/// Can't work properly if you're not building from an Apple device.
|
||||
#[serde(rename = "ios")]
|
||||
Ios,
|
||||
|
||||
/// Targeting the android bundle structure
|
||||
#[serde(rename = "android")]
|
||||
Android,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UnknownBundleFormatError;
|
||||
|
||||
impl std::error::Error for UnknownBundleFormatError {}
|
||||
|
||||
impl std::fmt::Display for UnknownBundleFormatError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Unknown bundle format")
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for BundleFormat {
|
||||
type Err = UnknownBundleFormatError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"web" => Ok(Self::Web),
|
||||
"macos" => Ok(Self::MacOS),
|
||||
"windows" => Ok(Self::Windows),
|
||||
"linux" => Ok(Self::Linux),
|
||||
"server" => Ok(Self::Server),
|
||||
"ios" => Ok(Self::Ios),
|
||||
"android" => Ok(Self::Android),
|
||||
_ => Err(UnknownBundleFormatError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BundleFormat {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
BundleFormat::Web => "web",
|
||||
BundleFormat::MacOS => "macos",
|
||||
BundleFormat::Windows => "windows",
|
||||
BundleFormat::Linux => "linux",
|
||||
BundleFormat::Server => "server",
|
||||
BundleFormat::Ios => "ios",
|
||||
BundleFormat::Android => "android",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl BundleFormat {
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Self::MacOS);
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Self::Windows);
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = Some(Self::Linux);
|
||||
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
|
||||
pub(crate) const TARGET_PLATFORM: Option<Self> = None;
|
||||
|
||||
/// Get the name of the folder we need to generate for this platform
|
||||
///
|
||||
/// Note that web and server share the same platform folder since we'll export the web folder as a bundle on its own
|
||||
pub(crate) fn build_folder_name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Web => "web",
|
||||
Self::Server => "web",
|
||||
Self::Ios => "ios",
|
||||
Self::Android => "android",
|
||||
Self::Windows => "windows",
|
||||
Self::Linux => "linux",
|
||||
Self::MacOS => "macos",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn profile_name(&self, release: bool) -> String {
|
||||
let base_profile = match self {
|
||||
Self::MacOS | Self::Windows | Self::Linux => "desktop",
|
||||
Self::Web => "wasm",
|
||||
Self::Ios => "ios",
|
||||
Self::Android => "android",
|
||||
Self::Server => "server",
|
||||
};
|
||||
|
||||
let opt_level = if release { "release" } else { "dev" };
|
||||
|
||||
format!("{base_profile}-{opt_level}")
|
||||
}
|
||||
|
||||
pub(crate) fn expected_name(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Web => "Web",
|
||||
Self::MacOS => "MacOS",
|
||||
Self::Windows => "Windows",
|
||||
Self::Linux => "Linux",
|
||||
Self::Ios => "iOS",
|
||||
Self::Android => "Android",
|
||||
Self::Server => "Server",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_target(target: &Triple, renderer: Option<Renderer>) -> Result<BundleFormat> {
|
||||
match (
|
||||
renderer,
|
||||
target.architecture,
|
||||
target.environment,
|
||||
target.operating_system,
|
||||
) {
|
||||
// The server always uses the server bundle format
|
||||
(Some(Renderer::Server), _, _, _) => Ok(BundleFormat::Server),
|
||||
// The web renderer always uses the web bundle format
|
||||
(Some(Renderer::Web), _, _, _) => Ok(BundleFormat::Web),
|
||||
// Otherwise, guess it based on the target
|
||||
// Assume any wasm32 or wasm64 target is a web target
|
||||
(_, Architecture::Wasm32 | Architecture::Wasm64, _, _) => Ok(BundleFormat::Web),
|
||||
// For native targets, we need to determine the bundle format based on the OS
|
||||
(_, _, Environment::Android, _) => Ok(BundleFormat::Android),
|
||||
(_, _, _, OperatingSystem::IOS(_)) => Ok(BundleFormat::Ios),
|
||||
(_, _, _, OperatingSystem::MacOSX(_) | OperatingSystem::Darwin(_)) => {
|
||||
Ok(BundleFormat::MacOS)
|
||||
}
|
||||
(_, _, _, OperatingSystem::Linux) => Ok(BundleFormat::Linux),
|
||||
(_, _, _, OperatingSystem::Windows) => Ok(BundleFormat::Windows),
|
||||
// If we don't recognize the target, default to desktop
|
||||
_ => BundleFormat::TARGET_PLATFORM.context(
|
||||
"failed to determine bundle format. Try setting the `--bundle` flag manually",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy,
|
||||
@@ -18,188 +496,74 @@ use std::str::FromStr;
|
||||
)]
|
||||
#[non_exhaustive]
|
||||
pub(crate) enum Platform {
|
||||
/// Targeting the web platform using WASM
|
||||
/// Alias for `--wasm --web --bundle-format web`
|
||||
#[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
|
||||
/// Alias for `--macos --webview --bundle-format macos`
|
||||
#[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
|
||||
/// Alias for `--windows --webview --bundle-format windows`
|
||||
#[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
|
||||
/// Alias for `--linux --webview --bundle-format linux`
|
||||
#[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.
|
||||
/// Alias for `--ios --webview --bundle-format ios`
|
||||
#[clap(name = "ios")]
|
||||
#[serde(rename = "ios")]
|
||||
Ios,
|
||||
|
||||
/// Targeting the android platform
|
||||
/// Alias for `--android --webview --bundle-format android`
|
||||
#[clap(name = "android")]
|
||||
#[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.
|
||||
/// Alias for `--host --server --bundle-format server`
|
||||
#[clap(name = "server")]
|
||||
#[serde(rename = "server")]
|
||||
Server,
|
||||
|
||||
/// Targeting the static generation platform using SSR and Dioxus-Fullstack
|
||||
/// Alias for `--host --liveview --bundle-format host`
|
||||
#[clap(name = "liveview")]
|
||||
#[serde(rename = "liveview")]
|
||||
Liveview,
|
||||
}
|
||||
|
||||
/// An error that occurs when a platform is not recognized
|
||||
pub(crate) struct UnknownPlatformError;
|
||||
|
||||
impl std::fmt::Display for UnknownPlatformError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Unknown platform")
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Platform {
|
||||
type Err = UnknownPlatformError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"web" => Ok(Self::Web),
|
||||
"macos" => Ok(Self::MacOS),
|
||||
"windows" => Ok(Self::Windows),
|
||||
"linux" => Ok(Self::Linux),
|
||||
"liveview" => Ok(Self::Liveview),
|
||||
"server" => Ok(Self::Server),
|
||||
"ios" => Ok(Self::Ios),
|
||||
"android" => Ok(Self::Android),
|
||||
_ => Err(UnknownPlatformError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Platform {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Platform::Web => "web",
|
||||
Platform::MacOS => "macos",
|
||||
Platform::Windows => "windows",
|
||||
Platform::Linux => "linux",
|
||||
Platform::Ios => "ios",
|
||||
Platform::Android => "android",
|
||||
Platform::Server => "server",
|
||||
Platform::Liveview => "liveview",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Platform {
|
||||
/// Get the feature name for the platform in the dioxus crate
|
||||
pub(crate) fn feature_name(&self) -> &str {
|
||||
pub(crate) fn into_triple(self) -> (TargetAlias, Renderer, BundleFormat) {
|
||||
match self {
|
||||
Platform::Web => "web",
|
||||
Platform::MacOS => "desktop",
|
||||
Platform::Windows => "desktop",
|
||||
Platform::Linux => "desktop",
|
||||
Platform::Server => "server",
|
||||
Platform::Liveview => "liveview",
|
||||
Platform::Ios => "mobile",
|
||||
Platform::Android => "mobile",
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the name of the folder we need to generate for this platform
|
||||
///
|
||||
/// Note that web and server share the same platform folder since we'll export the web folder as a bundle on its own
|
||||
pub(crate) fn build_folder_name(&self) -> &'static str {
|
||||
match self {
|
||||
Platform::Web => "web",
|
||||
Platform::Server => "web",
|
||||
Platform::Liveview => "liveview",
|
||||
Platform::Ios => "ios",
|
||||
Platform::Android => "android",
|
||||
Platform::Windows => "windows",
|
||||
Platform::Linux => "linux",
|
||||
Platform::MacOS => "macos",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expected_name(&self) -> &'static str {
|
||||
match self {
|
||||
Platform::Web => "Web",
|
||||
Platform::MacOS => "Desktop MacOS",
|
||||
Platform::Windows => "Desktop Windows",
|
||||
Platform::Linux => "Desktop Linux",
|
||||
Platform::Ios => "Mobile iOS",
|
||||
Platform::Android => "Mobile Android",
|
||||
Platform::Server => "Server",
|
||||
Platform::Liveview => "Liveview",
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
"mobile" => None,
|
||||
"liveview" => Some(Platform::Liveview),
|
||||
"server" => Some(Platform::Server),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn profile_name(&self, release: bool) -> String {
|
||||
let base_profile = match self {
|
||||
Platform::MacOS | Platform::Windows | Platform::Linux => "desktop",
|
||||
Platform::Web => "web",
|
||||
Platform::Ios => "ios",
|
||||
Platform::Android => "android",
|
||||
Platform::Server => "server",
|
||||
Platform::Liveview => "liveview",
|
||||
};
|
||||
|
||||
if release {
|
||||
format!("{}-release", base_profile)
|
||||
} else {
|
||||
format!("{}-dev", base_profile)
|
||||
Platform::Web => (TargetAlias::Wasm, Renderer::Web, BundleFormat::Web),
|
||||
Platform::MacOS => (TargetAlias::MacOS, Renderer::Webview, BundleFormat::MacOS),
|
||||
Platform::Windows => (
|
||||
TargetAlias::Windows,
|
||||
Renderer::Webview,
|
||||
BundleFormat::Windows,
|
||||
),
|
||||
Platform::Linux => (TargetAlias::Linux, Renderer::Webview, BundleFormat::Linux),
|
||||
Platform::Ios => (TargetAlias::Ios, Renderer::Webview, BundleFormat::Ios),
|
||||
Platform::Android => (
|
||||
TargetAlias::Android,
|
||||
Renderer::Webview,
|
||||
BundleFormat::Android,
|
||||
),
|
||||
Platform::Server => (TargetAlias::Host, Renderer::Server, BundleFormat::Server),
|
||||
Platform::Liveview => (
|
||||
TargetAlias::Host,
|
||||
Renderer::Liveview,
|
||||
BundleFormat::TARGET_PLATFORM.unwrap(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
styles::{GLOW_STYLE, LINK_STYLE},
|
||||
AppBuilder, BuildId, BuildMode, BuilderUpdate, Platform, Result, ServeArgs, TraceController,
|
||||
AppBuilder, BuildId, BuildMode, BuilderUpdate, BundleFormat, Result, ServeArgs,
|
||||
TraceController,
|
||||
};
|
||||
|
||||
mod ansi_buffer;
|
||||
@@ -122,15 +123,15 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
||||
|
||||
// Received a message from the devtools server - currently we only use this for
|
||||
// logging, so we just forward it the tui
|
||||
ServeUpdate::WsMessage { msg, platform } => {
|
||||
screen.push_ws_message(platform, &msg);
|
||||
ServeUpdate::WsMessage { msg, bundle } => {
|
||||
screen.push_ws_message(bundle, &msg);
|
||||
}
|
||||
|
||||
// Wait for logs from the build engine
|
||||
// These will cause us to update the screen
|
||||
// We also can check the status of the builds here in case we have multiple ongoing builds
|
||||
ServeUpdate::BuilderUpdate { id, update } => {
|
||||
let platform = builder.get_build(id).unwrap().build.platform;
|
||||
let bundle_format = builder.get_build(id).unwrap().build.bundle;
|
||||
|
||||
// Queue any logs to be printed if need be
|
||||
screen.new_build_update(&update);
|
||||
@@ -147,14 +148,14 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
||||
stage: BuildStage::Failed,
|
||||
} => {
|
||||
if exit_on_error {
|
||||
bail!("Build failed for platform: {platform}");
|
||||
bail!("Build failed for platform: {bundle_format}");
|
||||
}
|
||||
}
|
||||
BuilderUpdate::Progress {
|
||||
stage: BuildStage::Aborted,
|
||||
} => {
|
||||
if exit_on_error {
|
||||
bail!("Build aborted for platform: {platform}");
|
||||
bail!("Build aborted for platform: {bundle_format}");
|
||||
}
|
||||
}
|
||||
BuilderUpdate::Progress { .. } => {}
|
||||
@@ -206,22 +207,24 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
||||
}
|
||||
},
|
||||
BuilderUpdate::StdoutReceived { msg } => {
|
||||
screen.push_stdio(platform, msg, tracing::Level::INFO);
|
||||
screen.push_stdio(bundle_format, msg, tracing::Level::INFO);
|
||||
}
|
||||
BuilderUpdate::StderrReceived { msg } => {
|
||||
screen.push_stdio(platform, msg, tracing::Level::ERROR);
|
||||
screen.push_stdio(bundle_format, msg, tracing::Level::ERROR);
|
||||
}
|
||||
BuilderUpdate::ProcessExited { status } => {
|
||||
if status.success() {
|
||||
tracing::info!(
|
||||
r#"Application [{platform}] exited gracefully.
|
||||
r#"Application [{bundle_format}] exited gracefully.
|
||||
• To restart the app, press `r` to rebuild or `o` to open
|
||||
• To exit the server, press `ctrl+c`"#
|
||||
);
|
||||
} else {
|
||||
tracing::error!("Application [{platform}] exited with error: {status}");
|
||||
tracing::error!(
|
||||
"Application [{bundle_format}] exited with error: {status}"
|
||||
);
|
||||
if exit_on_error {
|
||||
bail!("Application [{platform}] exited with error: {status}");
|
||||
bail!("Application [{bundle_format}] exited with error: {status}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,7 +244,7 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) ->
|
||||
}
|
||||
|
||||
ServeUpdate::OpenApp => match builder.use_hotpatch_engine {
|
||||
true if !matches!(builder.client.build.platform, Platform::Web) => {
|
||||
true if !matches!(builder.client.build.bundle, BundleFormat::Web) => {
|
||||
tracing::warn!(
|
||||
"Opening a native app with hotpatching enabled requires a full rebuild..."
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
serve::{ansi_buffer::ansi_string_to_line, ServeUpdate, WebServer},
|
||||
BuildId, BuildStage, BuilderUpdate, Platform, TraceContent, TraceMsg, TraceSrc,
|
||||
BuildId, BuildStage, BuilderUpdate, BundleFormat, TraceContent, TraceMsg, TraceSrc,
|
||||
};
|
||||
use cargo_metadata::diagnostic::Diagnostic;
|
||||
use crossterm::{
|
||||
@@ -316,12 +316,12 @@ impl Output {
|
||||
/// Add a message from stderr to the logs
|
||||
/// This will queue the stderr message as a TraceMsg and print it on the next render
|
||||
/// We'll use the `App` TraceSrc for the msg, and whatever level is provided
|
||||
pub fn push_stdio(&mut self, platform: Platform, msg: String, level: Level) {
|
||||
self.push_log(TraceMsg::text(TraceSrc::App(platform), level, msg));
|
||||
pub fn push_stdio(&mut self, bundle: BundleFormat, msg: String, level: Level) {
|
||||
self.push_log(TraceMsg::text(TraceSrc::App(bundle), level, msg));
|
||||
}
|
||||
|
||||
/// Push a message from the websocket to the logs
|
||||
pub fn push_ws_message(&mut self, platform: Platform, message: &axum::extract::ws::Message) {
|
||||
pub fn push_ws_message(&mut self, bundle: BundleFormat, message: &axum::extract::ws::Message) {
|
||||
use dioxus_devtools_types::ClientMsg;
|
||||
|
||||
// We can only handle text messages from the websocket...
|
||||
@@ -336,7 +336,7 @@ impl Output {
|
||||
let msg = match res {
|
||||
Ok(msg) => msg,
|
||||
Err(err) => {
|
||||
tracing::error!(dx_src = ?TraceSrc::Dev, "Error parsing message from {}: {} -> {:?}", platform, err, text.as_str());
|
||||
tracing::error!(dx_src = ?TraceSrc::Dev, "Error parsing message from {}: {} -> {:?}", bundle, err, text.as_str());
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -358,7 +358,7 @@ impl Output {
|
||||
};
|
||||
|
||||
// We don't care about logging the app's message so we directly push it instead of using tracing.
|
||||
self.push_log(TraceMsg::text(TraceSrc::App(platform), level, content));
|
||||
self.push_log(TraceMsg::text(TraceSrc::App(bundle), level, content));
|
||||
}
|
||||
|
||||
/// Change internal state based on the build engine's update
|
||||
@@ -641,7 +641,7 @@ impl Output {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
"Platform: ".gray(),
|
||||
client.build.platform.expected_name().yellow(),
|
||||
client.build.bundle.expected_name().yellow(),
|
||||
if state.runner.is_fullstack() {
|
||||
" + fullstack".yellow()
|
||||
} else {
|
||||
@@ -672,7 +672,7 @@ impl Output {
|
||||
|
||||
frame.render_widget_ref(
|
||||
Paragraph::new(Line::from(vec![
|
||||
if client.build.platform == Platform::Web {
|
||||
if client.build.bundle == BundleFormat::Web {
|
||||
"Serving at: ".gray()
|
||||
} else {
|
||||
"Server at: ".gray()
|
||||
@@ -755,7 +755,7 @@ impl Output {
|
||||
);
|
||||
|
||||
let server_address = match state.server.server_address() {
|
||||
Some(address) => format!("http://{}", address).yellow(),
|
||||
Some(address) => format!("http://{address}").yellow(),
|
||||
None => "no address".dark_gray(),
|
||||
};
|
||||
frame.render_widget(
|
||||
@@ -770,7 +770,7 @@ impl Output {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
"Read the docs: ".gray(),
|
||||
"https://dioxuslabs.com/0.6/docs".blue(),
|
||||
"https://dioxuslabs.com/learn/0.7/".blue(),
|
||||
])),
|
||||
links_list[0],
|
||||
);
|
||||
|
||||
@@ -163,8 +163,7 @@ pub(crate) fn handle_proxy_error(e: Error) -> axum::http::Response<axum::body::B
|
||||
axum::http::Response::builder()
|
||||
.status(axum::http::StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(axum::body::Body::from(format!(
|
||||
"Proxy connection failed: {:#?}",
|
||||
e
|
||||
"Proxy connection failed: {e:#?}"
|
||||
)))
|
||||
.unwrap()
|
||||
}
|
||||
@@ -229,7 +228,7 @@ mod test {
|
||||
let server_addr = setup_servers(config).await;
|
||||
|
||||
assert_eq!(
|
||||
reqwest::get(format!("http://{}/api", server_addr))
|
||||
reqwest::get(format!("http://{server_addr}/api"))
|
||||
.await
|
||||
.unwrap()
|
||||
.text()
|
||||
@@ -239,7 +238,7 @@ mod test {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
reqwest::get(format!("http://{}/api/", server_addr))
|
||||
reqwest::get(format!("http://{server_addr}/api/"))
|
||||
.await
|
||||
.unwrap()
|
||||
.text()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{AppBuilder, ServeUpdate, WebServer};
|
||||
use crate::{
|
||||
platform_override::CommandWithPlatformOverrides, BuildArtifacts, BuildId, BuildMode,
|
||||
BuildTargets, BuilderUpdate, HotpatchModuleCache, Platform, Result, ServeArgs, TailwindCli,
|
||||
BuildTargets, BuilderUpdate, BundleFormat, HotpatchModuleCache, Result, ServeArgs, TailwindCli,
|
||||
TraceSrc, Workspace,
|
||||
};
|
||||
use anyhow::{bail, Context};
|
||||
@@ -151,8 +151,8 @@ impl AppServer {
|
||||
// All servers will end up behind us (the devserver) but on a different port
|
||||
// This is so we can serve a loading screen as well as devtools without anything particularly fancy
|
||||
let fullstack = server.is_some();
|
||||
let should_proxy_port = match client.platform {
|
||||
Platform::Server => true,
|
||||
let should_proxy_port = match client.bundle {
|
||||
BundleFormat::Server => true,
|
||||
_ => fullstack && !ssg,
|
||||
};
|
||||
|
||||
@@ -168,7 +168,7 @@ impl AppServer {
|
||||
|
||||
// Only start Tailwind watcher for client builds that serve assets (not server builds or fullstack mode)
|
||||
// In fullstack mode, the client build's prebuild() handles Tailwind generation to avoid race conditions
|
||||
let tw_watcher = if client.build.platform != Platform::Server && !fullstack {
|
||||
let tw_watcher = if client.build.bundle != BundleFormat::Server && !fullstack {
|
||||
TailwindCli::serve(
|
||||
client.build.package_manifest_dir(),
|
||||
client.build.config.application.tailwind_input.clone(),
|
||||
@@ -536,7 +536,8 @@ impl AppServer {
|
||||
use crate::styles::NOTE_STYLE;
|
||||
tracing::info!(dx_src = ?TraceSrc::Dev, "Hotreloading: {NOTE_STYLE}{}{NOTE_STYLE:#}", file);
|
||||
|
||||
if !server.has_hotreload_sockets() && self.client.build.platform != Platform::Web {
|
||||
if !server.has_hotreload_sockets() && self.client.build.bundle != BundleFormat::Web
|
||||
{
|
||||
tracing::warn!("No clients to hotreload - try reloading the app!");
|
||||
}
|
||||
|
||||
@@ -554,8 +555,8 @@ impl AppServer {
|
||||
devserver: &mut WebServer,
|
||||
) -> Result<()> {
|
||||
// Make sure to save artifacts regardless of if we're opening the app or not
|
||||
match artifacts.platform {
|
||||
Platform::Server => {
|
||||
match artifacts.bundle {
|
||||
BundleFormat::Server => {
|
||||
if let Some(server) = self.server.as_mut() {
|
||||
server.artifacts = Some(artifacts.clone());
|
||||
}
|
||||
@@ -661,7 +662,7 @@ impl AppServer {
|
||||
|
||||
// If the client is running on Android, we need to remove the port forwarding
|
||||
// todo: use the android tools "adb"
|
||||
if matches!(self.client.build.platform, Platform::Android) {
|
||||
if matches!(self.client.build.bundle, BundleFormat::Android) {
|
||||
if let Err(err) = Command::new(&self.workspace.android_tools()?.adb)
|
||||
.arg("reverse")
|
||||
.arg("--remove")
|
||||
@@ -786,7 +787,7 @@ impl AppServer {
|
||||
BuildId::CLIENT => {
|
||||
// multiple tabs on web can cause this to be called incorrectly, and it doesn't
|
||||
// make any sense anyways
|
||||
if self.client.build.platform != Platform::Web {
|
||||
if self.client.build.bundle != BundleFormat::Web {
|
||||
if let Some(aslr_reference) = aslr_reference {
|
||||
self.client.aslr_reference = Some(aslr_reference);
|
||||
}
|
||||
@@ -804,7 +805,7 @@ impl AppServer {
|
||||
}
|
||||
|
||||
// Assign the runtime asset dir to the runner
|
||||
if self.client.build.platform == Platform::Ios {
|
||||
if self.client.build.bundle == BundleFormat::Ios {
|
||||
// xcrun simctl get_app_container booted com.dioxuslabs
|
||||
let res = Command::new("xcrun")
|
||||
.arg("simctl")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
config::WebHttpsConfig, serve::ServeUpdate, BuildId, BuildStage, BuilderUpdate, Platform,
|
||||
config::WebHttpsConfig, serve::ServeUpdate, BuildId, BuildStage, BuilderUpdate, BundleFormat,
|
||||
Result, TraceSrc,
|
||||
};
|
||||
use anyhow::{bail, Context};
|
||||
@@ -62,7 +62,7 @@ pub(crate) struct WebServer {
|
||||
new_build_status_sockets: UnboundedReceiver<ConnectedWsClient>,
|
||||
build_status: SharedStatus,
|
||||
application_name: String,
|
||||
platform: Platform,
|
||||
bundle: BundleFormat,
|
||||
}
|
||||
|
||||
pub(crate) struct ConnectedWsClient {
|
||||
@@ -128,7 +128,7 @@ impl WebServer {
|
||||
new_hot_reload_sockets: hot_reload_sockets_rx,
|
||||
new_build_status_sockets: build_status_sockets_rx,
|
||||
application_name: runner.app_name().to_string(),
|
||||
platform: runner.client.build.platform,
|
||||
bundle: runner.client.build.bundle,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ impl WebServer {
|
||||
drop(new_message);
|
||||
|
||||
// Update the socket with project info and current build status
|
||||
let project_info = SharedStatus::new(Status::ClientInit { application_name: self.application_name.clone(), platform: self.platform });
|
||||
let project_info = SharedStatus::new(Status::ClientInit { application_name: self.application_name.clone(), bundle: self.bundle });
|
||||
if project_info.send_to(&mut new_socket.socket).await.is_ok() {
|
||||
_ = self.build_status.send_to(&mut new_socket.socket).await;
|
||||
self.build_status_sockets.push(new_socket);
|
||||
@@ -175,7 +175,7 @@ impl WebServer {
|
||||
}
|
||||
Some((idx, message)) = new_message.next() => {
|
||||
match message {
|
||||
Some(Ok(msg)) => return ServeUpdate::WsMessage { msg, platform: Platform::Web },
|
||||
Some(Ok(msg)) => return ServeUpdate::WsMessage { msg, bundle: BundleFormat::Web },
|
||||
_ => {
|
||||
drop(new_message);
|
||||
_ = self.hot_reload_sockets.remove(idx);
|
||||
@@ -375,8 +375,8 @@ impl WebServer {
|
||||
}
|
||||
|
||||
pub fn server_address(&self) -> Option<SocketAddr> {
|
||||
match self.platform {
|
||||
Platform::Web | Platform::Server => Some(self.devserver_address()),
|
||||
match self.bundle {
|
||||
BundleFormat::Web | BundleFormat::Server => Some(self.devserver_address()),
|
||||
_ => self.proxied_server_address(),
|
||||
}
|
||||
}
|
||||
@@ -461,8 +461,7 @@ fn build_devserver_router(
|
||||
Response::builder()
|
||||
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||
.body(Body::from(format!(
|
||||
"Backend connection failed. The backend is likely still starting up. Please try again in a few seconds. Error: {:#?}",
|
||||
error
|
||||
"Backend connection failed. The backend is likely still starting up. Please try again in a few seconds. Error: {error:#?}"
|
||||
)))
|
||||
.unwrap()
|
||||
},
|
||||
@@ -577,7 +576,7 @@ fn build_serve_dir(runner: &AppServer) -> axum::routing::MethodRouter {
|
||||
.handle_error(|error: Infallible| async move {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("Unhandled internal error: {}", error),
|
||||
format!("Unhandled internal error: {error}"),
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -730,7 +729,7 @@ struct SharedStatus(Arc<RwLock<Status>>);
|
||||
enum Status {
|
||||
ClientInit {
|
||||
application_name: String,
|
||||
platform: Platform,
|
||||
bundle: BundleFormat,
|
||||
},
|
||||
Building {
|
||||
progress: f64,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{BuildId, BuilderUpdate, Error, Platform, TraceMsg};
|
||||
use crate::{BuildId, BuilderUpdate, BundleFormat, Error, TraceMsg};
|
||||
use axum::extract::ws::Message as WsMessage;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -13,7 +13,7 @@ pub(crate) enum ServeUpdate {
|
||||
pid: Option<u32>,
|
||||
},
|
||||
WsMessage {
|
||||
platform: Platform,
|
||||
bundle: BundleFormat,
|
||||
msg: WsMessage,
|
||||
},
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ impl TailwindCli {
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(format!("tailwindcss-{}-{}", platform, arch))
|
||||
Some(format!("tailwindcss-{platform}-{arch}"))
|
||||
}
|
||||
|
||||
fn install_dir(&self) -> Result<PathBuf> {
|
||||
|
||||
Reference in new issue
Block a user