From 7d121d1650194cabb9815ad0917a421ae6111255 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 21 Oct 2026 09:43:53 +0800 Subject: [PATCH] Prebuild only the apps that open as a process The checkout prebuild planned a release build for every listed catalog app, including the linked modules this shell opens in-process (Calculator, Clock, Notes, Reminders and Weather on macOS): five builds no launch would ever start, run before the apps people open as a process got their turn on a fresh checkout. The plan now leaves out every app a launch would host in-process, by the rule launch_app_with_args applies (hosting Module and a linked module). Co-Authored-By: Claude Opus 5.5 --- crates/shell/src/lib.rs | 5 +++-- crates/shell/src/prebuild.rs | 33 +++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/crates/shell/src/lib.rs b/crates/shell/src/lib.rs index 74d952b2..01195c4a 100644 --- a/crates/shell/src/lib.rs +++ b/crates/shell/src/lib.rs @@ -6375,8 +6375,9 @@ impl MatchEvent for App { log!("octosense: background app prewarming disabled"); } // A checkout run builds its catalog apps in the background, so their - // first open needn't wait for cargo (prebuild.rs). - prebuild::start(&cx.thread_spawner()); + // first open needn't wait for cargo (prebuild.rs): those that open as + // a process, by the same rule `launch_app_with_args` applies. + prebuild::start(&cx.thread_spawner(), |id| self.apps.hosting(id) == Hosting::Module && self.apps.module(id).is_some()); // `--gallery`: the shell surfaces with fixture data instead of a // desktop, so the port is verifiable over --remote (shell/gallery.rs). diff --git a/crates/shell/src/prebuild.rs b/crates/shell/src/prebuild.rs index de1235a3..3f40c504 100644 --- a/crates/shell/src/prebuild.rs +++ b/crates/shell/src/prebuild.rs @@ -8,6 +8,9 @@ //! builds once in the background, shortly after the shell starts, so a //! later open finds its binary built and starts at once. //! +//! - Only apps that open as a process: a linked module the shell hosts +//! in-process (Calculator, Clock, Notes, Reminders and Weather on macOS) +//! never runs its process build, so the prebuild leaves it out. //! - One build at a time, in catalog order, each the exact command a launch //! would run ([`clients::build_command`]), at background priority //! (darwinbg on macOS, nice 19 elsewhere): it never competes with the @@ -80,9 +83,13 @@ pub fn enabled(no_prebuild: Option<&str>) -> bool { /// The builds to run: the launch build of every listed catalog app that has /// one, each identical build once, in catalog order. Empty for an installed -/// shell (no checkout, so no app has a build). -pub fn plan(apps: &[AppDef], root: Option<&Path>) -> Vec<(String, BuildStep)> { - plan_listed(apps, root, crate::apps::listed) +/// shell (no checkout, so no app has a build). An app this shell opens +/// in-process (`in_process`: a linked module it hosts, such as Calculator, +/// Clock, Notes, Reminders and Weather on macOS) never runs that build, so +/// it is left out: on a fresh checkout those were five release builds +/// nothing would start. +pub fn plan(apps: &[AppDef], root: Option<&Path>, in_process: impl Fn(&str) -> bool) -> Vec<(String, BuildStep)> { + plan_listed(apps, root, |id| crate::apps::listed(id) && !in_process(id)) } fn plan_listed(apps: &[AppDef], root: Option<&Path>, listed: impl Fn(&str) -> bool) -> Vec<(String, BuildStep)> { @@ -103,12 +110,13 @@ fn plan_listed(apps: &[AppDef], root: Option<&Path>, listed: impl Fn(&str) -> bo } /// Start the prebuild on a worker of its own, when this shell runs from a -/// checkout and nothing turned it off. -pub fn start(spawner: &ThreadSpawner) { +/// checkout and nothing turned it off. `in_process`: whether a launch of an +/// app id would open it in-process, as the WM decides it at launch. +pub fn start(spawner: &ThreadSpawner, in_process: impl Fn(&str) -> bool) { if !crate::host::processes_available() || !enabled(std::env::var("MAKEPAD_WM_NO_PREBUILD").ok().as_deref()) { return; } - let steps = plan(&clients::available_apps(), clients::repo_root().as_deref()); + let steps = plan(&clients::available_apps(), clients::repo_root().as_deref(), in_process); if steps.is_empty() { return; } @@ -275,4 +283,17 @@ mod tests { let steps = plan_listed(&[files()], Some(Path::new("/checkout")), |id| id != "files"); assert!(steps.is_empty(), "{steps:?}"); } + + /// Calculator, Clock, Notes, Reminders and Weather open in-process on + /// macOS: their process build would never start, so it never runs. + #[test] + fn an_app_hosted_in_process_is_not_prebuilt() { + let clock = || AppDef::app("clock", "Clock", "makepad-clock", "", "clock", clients::LaunchPolicy::OrFocus); + let root = Path::new("/checkout"); + assert_eq!(plan_listed(&[files(), clock()], Some(root), |_| true).len(), 2, "both have a launch build"); + let steps: Vec<_> = plan_listed(&[files(), clock()], Some(root), |id| id != "clock"); + assert_eq!(steps.iter().map(|(id, _)| id.as_str()).collect::>(), ["files"]); + assert_eq!(plan(&[clock()], Some(root), |_| false).len(), 1, "as a process it is prebuilt"); + assert!(plan(&[clock()], Some(root), |id| id == "clock").is_empty(), "in-process it is left out"); + } }