diff --git a/packages/hot-reload/src/lib.rs b/packages/hot-reload/src/lib.rs index 20cc70a9a..5c79f9731 100644 --- a/packages/hot-reload/src/lib.rs +++ b/packages/hot-reload/src/lib.rs @@ -7,7 +7,7 @@ use std::{ use dioxus_core::Template; use dioxus_rsx::{ - hot_reload::{FileMap, UpdateResult}, + hot_reload::{FileMap, FileMapBuildResult, UpdateResult}, HotReloadingContext, }; use interprocess::local_socket::{LocalSocketListener, LocalSocketStream}; @@ -141,17 +141,24 @@ pub fn init(cfg: Config) { let temp_file = std::env::temp_dir().join("@dioxusin"); let channels = Arc::new(Mutex::new(Vec::new())); - let file_map = Arc::new(Mutex::new(FileMap::::new_with_filter( - crate_dir.clone(), - |path| { - // skip excluded paths - excluded_paths.iter().any(|p| path.starts_with(p)) || + let FileMapBuildResult { + map: file_map, + errors, + } = FileMap::::create_with_filter(crate_dir.clone(), |path| { + // skip excluded paths + excluded_paths.iter().any(|p| path.starts_with(p)) || // respect .gitignore gitignore .matched_path_or_any_parents(path, path.is_dir()) .is_ignore() - }, - ))); + }) + .unwrap(); + for err in errors { + if log { + println!("hot reloading failed to initialize:\n{err:?}"); + } + } + let file_map = Arc::new(Mutex::new(file_map)); if let Ok(local_socket_stream) = LocalSocketListener::bind(temp_file.as_path()) { let aborted = Arc::new(Mutex::new(false)); @@ -283,7 +290,7 @@ pub fn init(cfg: Config) { .unwrap() .update_rsx(path, crate_dir.as_path()) { - UpdateResult::UpdatedRsx(msgs) => { + Ok(UpdateResult::UpdatedRsx(msgs)) => { for msg in msgs { let mut i = 0; while i < channels.len() { @@ -299,13 +306,20 @@ pub fn init(cfg: Config) { } } } - UpdateResult::NeedsRebuild => { + Ok(UpdateResult::NeedsRebuild) => { drop(channels); if rebuild() { return; } break; } + Err(err) => { + if log { + println!( + "hot reloading failed to update rsx:\n{err:?}" + ); + } + } } } } diff --git a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs index 156d64ce4..38c1d9105 100644 --- a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs +++ b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs @@ -17,6 +17,14 @@ pub enum UpdateResult { NeedsRebuild, } +/// The result of building a FileMap +pub struct FileMapBuildResult { + /// The FileMap that was built + pub map: FileMap, + /// Any errors that occurred while building the FileMap that were not fatal + pub errors: Vec, +} + pub struct FileMap { pub map: HashMap>)>, phantom: std::marker::PhantomData, @@ -24,46 +32,63 @@ pub struct FileMap { impl FileMap { /// Create a new FileMap from a crate directory - pub fn new(path: PathBuf) -> Self { - Self::new_with_filter(path, |_| false) + pub fn create(path: PathBuf) -> io::Result> { + Self::create_with_filter(path, |_| false) } /// Create a new FileMap from a crate directory - pub fn new_with_filter(path: PathBuf, mut filter: impl FnMut(&Path) -> bool) -> Self { + pub fn create_with_filter( + path: PathBuf, + mut filter: impl FnMut(&Path) -> bool, + ) -> io::Result> { + struct FileMapSearchResult { + map: HashMap>)>, + errors: Vec, + } fn find_rs_files( root: PathBuf, filter: &mut impl FnMut(&Path) -> bool, - ) -> io::Result>)>> { + ) -> io::Result { let mut files = HashMap::new(); + let mut errors = Vec::new(); if root.is_dir() { for entry in (fs::read_dir(root)?).flatten() { let path = entry.path(); if !filter(&path) { - files.extend(find_rs_files(path, filter)?); + let FileMapSearchResult { + map, + errors: child_errors, + } = find_rs_files(path, filter)?; + errors.extend(child_errors); + files.extend(map); } } } else if root.extension().and_then(|s| s.to_str()) == Some("rs") { if let Ok(mut file) = File::open(root.clone()) { let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); + file.read_to_string(&mut src)?; files.insert(root, (src, None)); } } - Ok(files) + Ok(FileMapSearchResult { map: files, errors }) } + let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?; let result = Self { - map: find_rs_files(path, &mut filter).unwrap(), + map, phantom: std::marker::PhantomData, }; - result + Ok(FileMapBuildResult { + map: result, + errors, + }) } /// Try to update the rsx in a file - pub fn update_rsx(&mut self, file_path: &Path, crate_dir: &Path) -> UpdateResult { - let mut file = File::open(file_path).unwrap(); + pub fn update_rsx(&mut self, file_path: &Path, crate_dir: &Path) -> io::Result { + let mut file = File::open(file_path)?; let mut src = String::new(); - file.read_to_string(&mut src).expect("Unable to read file"); + file.read_to_string(&mut src)?; if let Ok(syntax) = syn::parse_file(&src) { if let Some((old_src, template_slot)) = self.map.get_mut(file_path) { if let Ok(old) = syn::parse_file(old_src) { @@ -99,7 +124,7 @@ impl FileMap { { // dioxus cannot handle empty templates if template.roots.is_empty() { - return UpdateResult::NeedsRebuild; + return Ok(UpdateResult::NeedsRebuild); } else { // if the template is the same, don't send it if let Some(old_template) = template_slot { @@ -111,20 +136,25 @@ impl FileMap { messages.push(template); } } else { - return UpdateResult::NeedsRebuild; + return Ok(UpdateResult::NeedsRebuild); } } } } - return UpdateResult::UpdatedRsx(messages); + return Ok(UpdateResult::UpdatedRsx(messages)); } } } } else { // if this is a new file, rebuild the project - *self = FileMap::new(crate_dir.to_path_buf()); + let FileMapBuildResult { map, mut errors } = + FileMap::create(crate_dir.to_path_buf())?; + if let Some(err) = errors.pop() { + return Err(err); + } + *self = map; } } - UpdateResult::NeedsRebuild + Ok(UpdateResult::NeedsRebuild) } }