Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions packages/cli/src/serve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,30 +173,44 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &TraceController) -> Resu
return Err(err);
}
}
BuilderUpdate::BuildReady { bundle } => match bundle.mode {
BuildMode::Thin { ref cache, .. } => {
if let Err(err) =
builder.hotpatch(&bundle, id, cache, &mut devserver).await
{
tracing::error!("Failed to hot-patch app: {err}");

if let Some(_patching) =
err.downcast_ref::<crate::build::PatchError>()
BuilderUpdate::BuildReady { bundle } => {
match bundle.mode {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, I guess Rust format was there.

BuildMode::Thin { ref cache, .. } => {
if let Err(err) =
builder.hotpatch(&bundle, id, cache, &mut devserver).await
{
tracing::info!("Starting full rebuild: {err}");
builder.full_rebuild().await;
devserver.send_reload_start().await;
devserver.start_build().await;
tracing::error!("Failed to hot-patch app: {err}");

if let Some(_patching) =
err.downcast_ref::<crate::build::PatchError>()
{
tracing::info!("Starting full rebuild: {err}");
builder.full_rebuild().await;
devserver.send_reload_start().await;
devserver.start_build().await;
}
}
}
BuildMode::Base { .. } | BuildMode::Fat => {
_ = builder
.open(&bundle, &mut devserver)
.await
.inspect_err(|e| tracing::error!("Failed to open app: {}", e));
}
}
BuildMode::Base { .. } | BuildMode::Fat => {
_ = builder
.open(&bundle, &mut devserver)
.await
.inspect_err(|e| tracing::error!("Failed to open app: {}", e));

// Process any file changes that were queued while the build was in progress.
// This handles tools like stylance, tailwind, or sass that generate files
// in response to source changes - those changes would otherwise be lost.
let pending = builder.take_pending_file_changes();
if !pending.is_empty() {
tracing::debug!(
"Processing {} pending file changes after build",
pending.len()
);
builder.handle_file_change(&pending, &mut devserver).await;
}
},
}
BuilderUpdate::StdoutReceived { msg } => {
screen.push_stdio(bundle_format, msg, tracing::Level::INFO);
}
Expand Down
16 changes: 15 additions & 1 deletion packages/cli/src/serve/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ pub(crate) struct AppServer {

// Additional plugin-type tools
pub(crate) tw_watcher: tokio::task::JoinHandle<Result<()>>,

// File changes that arrived while a build was in progress, to be processed after build completes
pub(crate) pending_file_changes: Vec<PathBuf>,
}

pub(crate) struct CachedFile {
Expand Down Expand Up @@ -209,6 +212,7 @@ impl AppServer {
tw_watcher,
server_args,
client_args,
pending_file_changes: Vec::new(),
};

// Only register the hot-reload stuff if we're watching the filesystem
Expand Down Expand Up @@ -240,6 +244,12 @@ impl AppServer {
}
}

/// Take any pending file changes that were queued while a build was in progress.
/// Returns the files and clears the pending list.
pub(crate) fn take_pending_file_changes(&mut self) -> Vec<PathBuf> {
std::mem::take(&mut self.pending_file_changes)
}

pub(crate) async fn rebuild_ssg(&mut self, devserver: &WebServer) {
if self.client.stage != BuildStage::Success {
return;
Expand Down Expand Up @@ -348,10 +358,14 @@ impl AppServer {
self.client.stage,
BuildStage::Failed | BuildStage::Aborted | BuildStage::Success
) {
// Queue file changes that arrive during a build, so we can process them after the build completes.
// This prevents losing changes from tools like stylance, tailwind, or sass that generate files
// in response to source changes.
tracing::debug!(
"Ignoring file change: client is not ready to receive hotreloads. Files: {:#?}",
"Queueing file change: client is not ready to receive hotreloads. Files: {:#?}",
files
);
self.pending_file_changes.extend(files.iter().cloned());
return;
}

Expand Down
Loading