queue hot reload changes for future clients (#2843)
This commit is contained in:
1 parent
2f30c73678
commit
1e03e3946d
3 files changed
+71
-7
No files matched your search
@@ -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
|
// We're going to kick off a new build, interrupting the current build if it's ongoing
|
||||||
builder.build();
|
builder.build();
|
||||||
|
|
||||||
|
// Clear the hot reload changes
|
||||||
|
watcher.clear_hot_reload_changes();
|
||||||
|
|
||||||
// Tell the server to show a loading page for any new requests
|
// Tell the server to show a loading page for any new requests
|
||||||
server.start_build().await;
|
server.start_build().await;
|
||||||
}
|
}
|
||||||
@@ -105,8 +108,16 @@ pub async fn serve_all(
|
|||||||
msg = server.wait() => {
|
msg = server.wait() => {
|
||||||
// Run the server in the background
|
// Run the server in the background
|
||||||
// Waiting for updates here lets us tap into when clients are added/removed
|
// Waiting for updates here lets us tap into when clients are added/removed
|
||||||
if let Some(msg) = msg {
|
match msg {
|
||||||
screen.new_ws_message(TargetPlatform::Web, 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 => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ use tower_http::{
|
|||||||
ServiceBuilderExt,
|
ServiceBuilderExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub enum ServerUpdate {
|
||||||
|
NewConnection,
|
||||||
|
Message(Message),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", content = "data")]
|
#[serde(tag = "type", content = "data")]
|
||||||
enum Status {
|
enum Status {
|
||||||
@@ -231,7 +236,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for new clients to be connected and then save them
|
/// 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_hot_reload_socket = self.new_hot_reload_sockets.next();
|
||||||
let mut new_build_status_socket = self.new_build_status_sockets.next();
|
let mut new_build_status_socket = self.new_build_status_sockets.next();
|
||||||
let mut new_message = self
|
let mut new_message = self
|
||||||
@@ -247,7 +252,7 @@ impl Server {
|
|||||||
if let Some(new_socket) = new_hot_reload_socket {
|
if let Some(new_socket) = new_hot_reload_socket {
|
||||||
drop(new_message);
|
drop(new_message);
|
||||||
self.hot_reload_sockets.push(new_socket);
|
self.hot_reload_sockets.push(new_socket);
|
||||||
return None;
|
return Some(ServerUpdate::NewConnection);
|
||||||
} else {
|
} else {
|
||||||
panic!("Could not receive a socket - the devtools could not boot - the port is likely already in use");
|
panic!("Could not receive a socket - the devtools could not boot - the port is likely already in use");
|
||||||
}
|
}
|
||||||
@@ -269,7 +274,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
(idx, message) = next_new_message => {
|
(idx, message) = next_new_message => {
|
||||||
match message {
|
match message {
|
||||||
Some(Ok(message)) => return Some(message),
|
Some(Ok(message)) => return Some(ServerUpdate::Message(message)),
|
||||||
_ => {
|
_ => {
|
||||||
drop(new_message);
|
drop(new_message);
|
||||||
_ = self.hot_reload_sockets.remove(idx);
|
_ = self.hot_reload_sockets.remove(idx);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::{fs, path::PathBuf, time::Duration};
|
use std::{fs, path::PathBuf, time::Duration};
|
||||||
|
|
||||||
use crate::serve::hot_reloading_file_map::FileMap;
|
use crate::serve::hot_reloading_file_map::FileMap;
|
||||||
@@ -24,6 +25,7 @@ pub struct Watcher {
|
|||||||
queued_events: Vec<notify::Event>,
|
queued_events: Vec<notify::Event>,
|
||||||
file_map: FileMap,
|
file_map: FileMap,
|
||||||
ignore: Gitignore,
|
ignore: Gitignore,
|
||||||
|
applied_hot_reload_message: Option<HotReloadMsg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Watcher {
|
impl Watcher {
|
||||||
@@ -132,6 +134,7 @@ impl Watcher {
|
|||||||
ignore,
|
ignore,
|
||||||
queued_events: Vec::new(),
|
queued_events: Vec::new(),
|
||||||
_last_update_time: chrono::Local::now().timestamp(),
|
_last_update_time: chrono::Local::now().timestamp(),
|
||||||
|
applied_hot_reload_message: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,11 +254,56 @@ impl Watcher {
|
|||||||
templates.extend(hotreloaded_templates);
|
templates.extend(hotreloaded_templates);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(HotReloadMsg {
|
let msg = HotReloadMsg {
|
||||||
templates,
|
templates,
|
||||||
assets,
|
assets,
|
||||||
unknown_files,
|
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
|
/// Ensure the changes we've received from the queue are actually legit changes to either assets or
|
||||||
|
|||||||
Reference in new issue
Block a user