Skip to content

Commit

Permalink
Make desktop fullstack work with the CLI (#2862)
Browse files Browse the repository at this point in the history
* Make desktop fullstack work with the CLI
* Simplify desktop fullstack example
* move the profiles to the workspace
  • Loading branch information
ealmloff authored Aug 20, 2024
1 parent 6a46a66 commit 5a7a913
Show file tree
Hide file tree
Showing 23 changed files with 239 additions and 259 deletions.
10 changes: 10 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,13 @@
DIOXUS_FRONT_ISSUER_URL = ""
DIOXUS_FRONT_CLIENT_ID = ""
DIOXUS_FRONT_URL = ""

[profile]

[profile.dioxus-client]
inherits = "dev"
opt-level = 2

[profile.dioxus-server]
inherits = "dev"
opt-level = 2
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ once_cell = "1.19.0"
# plugin packages
open = "5.0.1"
cargo-generate = "=0.21.1"
toml_edit = "0.22.15"
toml_edit = "0.22.20"

# bundling
tauri-bundler = { workspace = true }
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/builder/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ impl BuildRequest {
Ok(Some(assets))
})
.await
.unwrap()
.map_err(|e| anyhow::anyhow!(e))?
}

pub fn copy_assets_dir(&self) -> anyhow::Result<()> {
Expand All @@ -257,6 +257,7 @@ impl BuildRequest {
match self.build_arguments.platform {
Some(Platform::Fullstack | Platform::StaticGeneration) => match self.target_platform {
TargetPlatform::Web => out_dir.join("public"),
TargetPlatform::Desktop => out_dir.join("desktop"),
_ => out_dir,
},
_ => out_dir,
Expand Down
109 changes: 66 additions & 43 deletions packages/cli/src/builder/fullstack.rs
Original file line number Diff line number Diff line change
@@ -1,105 +1,128 @@
use toml_edit::Item;

use crate::builder::Build;
use crate::dioxus_crate::DioxusCrate;

use crate::builder::BuildRequest;
use std::path::PathBuf;
use std::io::Write;

use super::TargetPlatform;

static CLIENT_RUST_FLAGS: &[&str] = &["-Cdebuginfo=none", "-Cstrip=debuginfo"];
static CLIENT_PROFILE: &str = "dioxus-client";
static SERVER_PROFILE: &str = "dioxus-server";

// The `opt-level=2` increases build times, but can noticeably decrease time
// between saving changes and being able to interact with an app. The "overall"
// time difference (between having and not having the optimization) can be
// almost imperceptible (~1 s) but also can be very noticeable (~6 s) — depends
// on setup (hardware, OS, browser, idle load).
static SERVER_RUST_FLAGS: &[&str] = &["-O"];
static DEBUG_RUST_FLAG: &str = "-Cdebug-assertions";
// Find or create the client and server profiles in the .cargo/config.toml file
fn initialize_profiles(config: &DioxusCrate) -> crate::Result<()> {
let config_path = config.workspace_dir().join(".cargo/config.toml");
let mut config = match std::fs::read_to_string(&config_path) {
Ok(config) => config.parse::<toml_edit::DocumentMut>().map_err(|e| {
crate::Error::Other(anyhow::anyhow!("Failed to parse .cargo/config.toml: {}", e))
})?,
Err(_) => Default::default(),
};

fn add_debug_rust_flags(build: &Build, flags: &mut Vec<String>) {
if !build.release {
flags.push(DEBUG_RUST_FLAG.to_string());
}
}
if let Item::Table(table) = config
.as_table_mut()
.entry("profile")
.or_insert(Item::Table(Default::default()))
{
if let toml_edit::Entry::Vacant(entry) = table.entry(CLIENT_PROFILE) {
let mut client = toml_edit::Table::new();
client.insert("inherits", Item::Value("dev".into()));
client.insert("opt-level", Item::Value(2.into()));
entry.insert(Item::Table(client));
}

fn fullstack_rust_flags(build: &Build, base_flags: &[&str]) -> Vec<String> {
// If we are forcing debug mode, don't add any debug flags
if build.force_debug {
return Default::default();
if let toml_edit::Entry::Vacant(entry) = table.entry(SERVER_PROFILE) {
let mut server = toml_edit::Table::new();
server.insert("inherits", Item::Value("dev".into()));
server.insert("opt-level", Item::Value(2.into()));
entry.insert(Item::Table(server));
}
}

let mut rust_flags = base_flags.iter().map(ToString::to_string).collect();
add_debug_rust_flags(build, &mut rust_flags);
rust_flags
}
// Write the config back to the file
if let Some(parent) = config_path.parent() {
std::fs::create_dir_all(parent)?;
}
let file = std::fs::File::create(config_path)?;
let mut buf_writer = std::io::BufWriter::new(file);
write!(buf_writer, "{}", config)?;

// Fullstack builds run the server and client builds parallel by default
// To make them run in parallel, we need to set up different target directories for the server and client within /.dioxus
fn get_target_directory(build: &Build, target: PathBuf) -> Option<PathBuf> {
(!build.force_sequential).then_some(target)
Ok(())
}

impl BuildRequest {
pub(crate) fn new_fullstack(
config: DioxusCrate,
build_arguments: Build,
serve: bool,
) -> Vec<Self> {
vec![
) -> Result<Vec<Self>, crate::Error> {
initialize_profiles(&config)?;

Ok(vec![
Self::new_client(serve, &config, &build_arguments),
Self::new_server(serve, &config, &build_arguments),
]
])
}

fn new_with_target_directory_rust_flags_and_features(
serve: bool,
config: &DioxusCrate,
build: &Build,
target_directory: PathBuf,
rust_flags: &[&str],
feature: String,
feature: Option<String>,
target_platform: TargetPlatform,
) -> Self {
let config = config.clone();
let mut build = build.clone();
// Set the target directory we are building the server in
let target_dir = get_target_directory(&build, target_directory);
// Add the server feature to the features we pass to the build
build.target_args.features.push(feature);
if let Some(feature) = feature {
build.target_args.features.push(feature);
}

// Add the server flags to the build arguments
let rust_flags = fullstack_rust_flags(&build, rust_flags);

Self {
serve,
build_arguments: build.clone(),
dioxus_crate: config,
rust_flags,
target_dir,
rust_flags: Default::default(),
target_dir: None,
target_platform,
}
}

fn new_server(serve: bool, config: &DioxusCrate, build: &Build) -> Self {
let mut build = build.clone();
if build.profile.is_none() {
build.profile = Some(CLIENT_PROFILE.to_string());
}
let client_feature = build.auto_detect_server_feature(config);
Self::new_with_target_directory_rust_flags_and_features(
serve,
config,
build,
config.server_target_dir(),
SERVER_RUST_FLAGS,
build.target_args.server_feature.clone(),
&build,
build.target_args.server_feature.clone().or(client_feature),
TargetPlatform::Server,
)
}

fn new_client(serve: bool, config: &DioxusCrate, build: &Build) -> Self {
let mut build = build.clone();
if build.profile.is_none() {
build.profile = Some(SERVER_PROFILE.to_string());
}
let (client_feature, client_platform) = build.auto_detect_client_platform(config);
Self::new_with_target_directory_rust_flags_and_features(
serve,
config,
build,
config.client_target_dir(),
CLIENT_RUST_FLAGS,
build.target_args.client_feature.clone(),
TargetPlatform::Web,
&build,
build.target_args.client_feature.clone().or(client_feature),
client_platform,
)
}
}
25 changes: 20 additions & 5 deletions packages/cli/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use dioxus_cli_config::{Platform, RuntimeCLIArguments};
use futures_util::stream::select_all;
use futures_util::StreamExt;
use std::net::SocketAddr;
use std::str::FromStr;
use std::{path::PathBuf, process::Stdio};
use tokio::process::{Child, Command};

Expand All @@ -29,6 +30,20 @@ pub enum TargetPlatform {
Liveview,
}

impl FromStr for TargetPlatform {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"web" => Ok(Self::Web),
"desktop" => Ok(Self::Desktop),
"axum" | "server" => Ok(Self::Server),
"liveview" => Ok(Self::Liveview),
_ => Err(()),
}
}
}

impl std::fmt::Display for TargetPlatform {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down Expand Up @@ -62,7 +77,7 @@ impl BuildRequest {
serve: bool,
dioxus_crate: &DioxusCrate,
build_arguments: impl Into<Build>,
) -> Vec<Self> {
) -> crate::Result<Vec<Self>> {
let build_arguments = build_arguments.into();
let platform = build_arguments.platform();
let single_platform = |platform| {
Expand All @@ -76,15 +91,15 @@ impl BuildRequest {
target_dir: Default::default(),
}]
};
match platform {
Platform::Web => single_platform(TargetPlatform::Web),
Ok(match platform {
Platform::Liveview => single_platform(TargetPlatform::Liveview),
Platform::Web => single_platform(TargetPlatform::Web),
Platform::Desktop => single_platform(TargetPlatform::Desktop),
Platform::StaticGeneration | Platform::Fullstack => {
Self::new_fullstack(dioxus_crate.clone(), build_arguments, serve)
Self::new_fullstack(dioxus_crate.clone(), build_arguments, serve)?
}
_ => unimplemented!("Unknown platform: {platform:?}"),
}
})
}

pub(crate) async fn build_all_parallel(
Expand Down
Loading

0 comments on commit 5a7a913

Please sign in to comment.