Skip to content

Commit

Permalink
queue hot reload changes for future clients (#2843)
Browse files Browse the repository at this point in the history
  • Loading branch information
ealmloff authored Aug 14, 2024
1 parent 2f30c73 commit 1e03e39
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 7 deletions.
15 changes: 13 additions & 2 deletions packages/cli/src/serve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ pub async fn serve_all(
// We're going to kick off a new build, interrupting the current build if it's ongoing
builder.build();

// Clear the hot reload changes
watcher.clear_hot_reload_changes();

// Tell the server to show a loading page for any new requests
server.start_build().await;
}
Expand All @@ -105,8 +108,16 @@ pub async fn serve_all(
msg = server.wait() => {
// Run the server in the background
// Waiting for updates here lets us tap into when clients are added/removed
if let Some(msg) = msg {
screen.new_ws_message(TargetPlatform::Web, msg);
match msg {
Some(ServerUpdate::NewConnection) => {
if let Some(msg) = watcher.applied_hot_reload_changes() {
server.send_hotreload(msg).await;
}
}
Some(ServerUpdate::Message(msg)) => {
screen.new_ws_message(TargetPlatform::Web, msg);
}
None => {}
}
}

Expand Down
11 changes: 8 additions & 3 deletions packages/cli/src/serve/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ use tower_http::{
ServiceBuilderExt,
};

pub enum ServerUpdate {
NewConnection,
Message(Message),
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", content = "data")]
enum Status {
Expand Down Expand Up @@ -231,7 +236,7 @@ impl Server {
}

/// Wait for new clients to be connected and then save them
pub async fn wait(&mut self) -> Option<Message> {
pub async fn wait(&mut self) -> Option<ServerUpdate> {
let mut new_hot_reload_socket = self.new_hot_reload_sockets.next();
let mut new_build_status_socket = self.new_build_status_sockets.next();
let mut new_message = self
Expand All @@ -247,7 +252,7 @@ impl Server {
if let Some(new_socket) = new_hot_reload_socket {
drop(new_message);
self.hot_reload_sockets.push(new_socket);
return None;
return Some(ServerUpdate::NewConnection);
} else {
panic!("Could not receive a socket - the devtools could not boot - the port is likely already in use");
}
Expand All @@ -269,7 +274,7 @@ impl Server {
}
(idx, message) = next_new_message => {
match message {
Some(Ok(message)) => return Some(message),
Some(Ok(message)) => return Some(ServerUpdate::Message(message)),
_ => {
drop(new_message);
_ = self.hot_reload_sockets.remove(idx);
Expand Down
52 changes: 50 additions & 2 deletions packages/cli/src/serve/watcher.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::{HashMap, HashSet};
use std::{fs, path::PathBuf, time::Duration};

use crate::serve::hot_reloading_file_map::FileMap;
Expand All @@ -24,6 +25,7 @@ pub struct Watcher {
queued_events: Vec<notify::Event>,
file_map: FileMap,
ignore: Gitignore,
applied_hot_reload_message: Option<HotReloadMsg>,
}

impl Watcher {
Expand Down Expand Up @@ -132,6 +134,7 @@ impl Watcher {
ignore,
queued_events: Vec::new(),
_last_update_time: chrono::Local::now().timestamp(),
applied_hot_reload_message: None,
}
}

Expand Down Expand Up @@ -251,11 +254,56 @@ impl Watcher {
templates.extend(hotreloaded_templates);
}

Some(HotReloadMsg {
let msg = HotReloadMsg {
templates,
assets,
unknown_files,
})
};

self.add_hot_reload_message(&msg);

Some(msg)
}

/// Get any hot reload changes that have been applied since the last full rebuild
pub fn applied_hot_reload_changes(&mut self) -> Option<HotReloadMsg> {
self.applied_hot_reload_message.clone()
}

/// Clear the hot reload changes. This should be called any time a new build is starting
pub fn clear_hot_reload_changes(&mut self) {
self.applied_hot_reload_message.take();
}

/// Store the hot reload changes for any future clients that connect
fn add_hot_reload_message(&mut self, msg: &HotReloadMsg) {
match &mut self.applied_hot_reload_message {
Some(applied) => {
// Merge the assets, unknown files, and templates
// We keep the newer change if there is both a old and new change
let mut templates: HashMap<String, _> = std::mem::take(&mut applied.templates)
.into_iter()
.map(|template| (template.location.clone(), template))
.collect();
let mut assets: HashSet<PathBuf> =
std::mem::take(&mut applied.assets).into_iter().collect();
let mut unknown_files: HashSet<PathBuf> =
std::mem::take(&mut applied.unknown_files)
.into_iter()
.collect();
for template in &msg.templates {
templates.insert(template.location.clone(), template.clone());
}
assets.extend(msg.assets.iter().cloned());
unknown_files.extend(msg.unknown_files.iter().cloned());
applied.templates = templates.into_values().collect();
applied.assets = assets.into_iter().collect();
applied.unknown_files = unknown_files.into_iter().collect();
}
None => {
self.applied_hot_reload_message = Some(msg.clone());
}
}
}

/// Ensure the changes we've received from the queue are actually legit changes to either assets or
Expand Down

0 comments on commit 1e03e39

Please sign in to comment.