deduplicate serve code with hot reloading in the CLI crate

This commit is contained in:
Evan Almloff committed 2023-09-09 16:18:52 -05:00
1 parent c8127e164b
commit 49a127b31e
5 files changed
+153 -296

No files matched your search

+78 -122
View File
@@ -9,7 +9,7 @@ use std::{
path::PathBuf,
sync::{Arc, Mutex},
};
use tokio::sync::broadcast::Sender;
use tokio::sync::broadcast::{self};
mod output;
use output::*;
@@ -21,6 +21,7 @@ async fn setup_file_watcher<F: Fn() -> Result<BuildResult> + Send + 'static>(
build_with: F,
config: &CrateConfig,
web_info: Option<WebServerInfo>,
hot_reload: Option<HotReloadState>,
) -> Result<RecommendedWatcher> {
let mut last_update_time = chrono::Local::now().timestamp();
@@ -38,28 +39,81 @@ async fn setup_file_watcher<F: Fn() -> Result<BuildResult> + Send + 'static>(
let config = watcher_config.clone();
if let Ok(e) = info {
if chrono::Local::now().timestamp() > last_update_time {
match build_with() {
Ok(res) => {
last_update_time = chrono::Local::now().timestamp();
let mut needs_full_rebuild;
if let Some(hot_reload) = &hot_reload {
// find changes to the rsx in the file
let mut rsx_file_map = hot_reload.file_map.lock().unwrap();
let mut messages: Vec<Template<'static>> = Vec::new();
#[allow(clippy::redundant_clone)]
print_console_info(
&config,
PrettierOptions {
changed: e.paths.clone(),
warnings: res.warnings,
elapsed_time: res.elapsed_time,
},
web_info.clone(),
);
// In hot reload mode, we only need to rebuild if non-rsx code is changed
needs_full_rebuild = false;
#[cfg(feature = "plugin")]
let _ = PluginManager::on_serve_rebuild(
chrono::Local::now().timestamp(),
e.paths,
);
for path in &e.paths {
// if this is not a rust file, rebuild the whole project
if path.extension().and_then(|p| p.to_str()) != Some("rs") {
needs_full_rebuild = true;
break;
}
match rsx_file_map.update_rsx(path, &config.crate_dir) {
Ok(UpdateResult::UpdatedRsx(msgs)) => {
messages.extend(msgs);
needs_full_rebuild = false;
}
Ok(UpdateResult::NeedsRebuild) => {
needs_full_rebuild = true;
}
Err(err) => {
log::error!("{}", err);
}
}
}
if needs_full_rebuild {
// Reset the file map to the new state of the project
let FileMapBuildResult {
map: new_file_map,
errors,
} = FileMap::<HtmlCtx>::create(config.crate_dir.clone()).unwrap();
for err in errors {
log::error!("{}", err);
}
*rsx_file_map = new_file_map;
} else {
for msg in messages {
let _ = hot_reload.messages.send(msg);
}
}
} else {
needs_full_rebuild = true;
}
if needs_full_rebuild {
match build_with() {
Ok(res) => {
last_update_time = chrono::Local::now().timestamp();
#[allow(clippy::redundant_clone)]
print_console_info(
&config,
PrettierOptions {
changed: e.paths.clone(),
warnings: res.warnings,
elapsed_time: res.elapsed_time,
},
web_info.clone(),
);
#[cfg(feature = "plugin")]
let _ = PluginManager::on_serve_rebuild(
chrono::Local::now().timestamp(),
e.paths,
);
}
Err(e) => log::error!("{}", e),
}
Err(e) => log::error!("{}", e),
}
}
}
@@ -77,106 +131,8 @@ async fn setup_file_watcher<F: Fn() -> Result<BuildResult> + Send + 'static>(
Ok(watcher)
}
// Todo: reduce duplication and merge with setup_file_watcher()
/// Sets up a file watcher with hot reload
async fn setup_file_watcher_hot_reload<F: Fn() -> Result<BuildResult> + Send + 'static>(
config: &CrateConfig,
hot_reload_tx: Sender<Template<'static>>,
file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
build_with: F,
web_info: Option<WebServerInfo>,
) -> Result<RecommendedWatcher> {
// file watcher: check file change
let allow_watch_path = config
.dioxus_config
.web
.watcher
.watch_path
.clone()
.unwrap_or_else(|| vec![PathBuf::from("src")]);
let watcher_config = config.clone();
let mut last_update_time = chrono::Local::now().timestamp();
let mut watcher = RecommendedWatcher::new(
move |evt: notify::Result<notify::Event>| {
let config = watcher_config.clone();
// Give time for the change to take effect before reading the file
std::thread::sleep(std::time::Duration::from_millis(100));
if chrono::Local::now().timestamp() > last_update_time {
if let Ok(evt) = evt {
let mut messages: Vec<Template<'static>> = Vec::new();
for path in evt.paths.clone() {
// if this is not a rust file, rebuild the whole project
if path.extension().and_then(|p| p.to_str()) != Some("rs") {
match build_with() {
Ok(res) => {
print_console_info(
&config,
PrettierOptions {
changed: evt.paths,
warnings: res.warnings,
elapsed_time: res.elapsed_time,
},
web_info.clone(),
);
}
Err(err) => {
log::error!("{}", err);
}
}
return;
}
// find changes to the rsx in the file
let mut map = file_map.lock().unwrap();
match map.update_rsx(&path, &config.crate_dir) {
Ok(UpdateResult::UpdatedRsx(msgs)) => {
messages.extend(msgs);
}
Ok(UpdateResult::NeedsRebuild) => {
match build_with() {
Ok(res) => {
print_console_info(
&config,
PrettierOptions {
changed: evt.paths,
warnings: res.warnings,
elapsed_time: res.elapsed_time,
},
web_info.clone(),
);
}
Err(err) => {
log::error!("{}", err);
}
}
return;
}
Err(err) => {
log::error!("{}", err);
}
}
}
for msg in messages {
let _ = hot_reload_tx.send(msg);
}
}
last_update_time = chrono::Local::now().timestamp();
}
},
notify::Config::default(),
)
.unwrap();
for sub_path in allow_watch_path {
if let Err(err) = watcher.watch(
&config.crate_dir.join(&sub_path),
notify::RecursiveMode::Recursive,
) {
log::error!("error watching {sub_path:?}: \n{}", err);
}
}
Ok(watcher)
#[derive(Clone)]
pub struct HotReloadState {
pub messages: broadcast::Sender<Template<'static>>,
pub file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
}