From 0e749f00a35ac0bc852cc57d03efb6c40815ad33 Mon Sep 17 00:00:00 2001 From: jinrui Date: Wed, 18 Dec 2024 17:45:10 +0800 Subject: [PATCH] feat: persistent cache expose error to compilation.diagnostic (#8765) --- crates/rspack_core/src/cache/disable.rs | 5 +- crates/rspack_core/src/cache/mod.rs | 39 ++++++------- .../rspack_core/src/cache/persistent/mod.rs | 36 ++++++------ .../persistent/occasion/make/dependencies.rs | 28 ++++------ .../cache/persistent/occasion/make/meta.rs | 22 ++++---- .../src/cache/persistent/occasion/make/mod.rs | 12 ++-- .../persistent/occasion/make/module_graph.rs | 7 ++- .../src/cache/persistent/snapshot/mod.rs | 48 ++++++++-------- .../src/cache/persistent/snapshot/strategy.rs | 56 ++++++++++++------- .../src/cache/persistent/version.rs | 19 ++++--- crates/rspack_core/src/compiler/hmr.rs | 8 ++- crates/rspack_core/src/compiler/mod.rs | 19 +++++-- 12 files changed, 167 insertions(+), 132 deletions(-) diff --git a/crates/rspack_core/src/cache/disable.rs b/crates/rspack_core/src/cache/disable.rs index ea64109c460..708e3802093 100644 --- a/crates/rspack_core/src/cache/disable.rs +++ b/crates/rspack_core/src/cache/disable.rs @@ -1,3 +1,5 @@ +use rspack_error::Result; + use super::Cache; use crate::make::MakeArtifact; @@ -9,7 +11,8 @@ pub struct DisableCache; #[async_trait::async_trait] impl Cache for DisableCache { - async fn before_make(&self, make_artifact: &mut MakeArtifact) { + async fn before_make(&self, make_artifact: &mut MakeArtifact) -> Result<()> { *make_artifact = Default::default(); + Ok(()) } } diff --git a/crates/rspack_core/src/cache/mod.rs b/crates/rspack_core/src/cache/mod.rs index d8ddb7c64d1..2e51259d06a 100644 --- a/crates/rspack_core/src/cache/mod.rs +++ b/crates/rspack_core/src/cache/mod.rs @@ -4,6 +4,7 @@ pub mod persistent; use std::{fmt::Debug, sync::Arc}; +use rspack_error::Result; use rspack_fs::{FileSystem, IntermediateFileSystem}; pub use self::{disable::DisableCache, memory::MemoryCache, persistent::PersistentCache}; @@ -23,11 +24,19 @@ use crate::{make::MakeArtifact, Compilation, CompilerOptions, ExperimentCacheOpt /// We can consider change to Hook when we need to open the API to js side. #[async_trait::async_trait] pub trait Cache: Debug + Send + Sync { - async fn before_compile(&self, _compilation: &mut Compilation) {} - fn after_compile(&self, _compilation: &Compilation) {} + async fn before_compile(&self, _compilation: &mut Compilation) -> Result<()> { + Ok(()) + } + async fn after_compile(&self, _compilation: &Compilation) -> Result<()> { + Ok(()) + } - async fn before_make(&self, _make_artifact: &mut MakeArtifact) {} - fn after_make(&self, _make_artifact: &MakeArtifact) {} + async fn before_make(&self, _make_artifact: &mut MakeArtifact) -> Result<()> { + Ok(()) + } + async fn after_make(&self, _make_artifact: &MakeArtifact) -> Result<()> { + Ok(()) + } } pub fn new_cache( @@ -39,20 +48,12 @@ pub fn new_cache( match &compiler_option.experiments.cache { ExperimentCacheOptions::Disabled => Arc::new(DisableCache), ExperimentCacheOptions::Memory => Arc::new(MemoryCache), - ExperimentCacheOptions::Persistent(option) => { - match PersistentCache::new( - compiler_path, - option, - compiler_option.clone(), - input_filesystem, - intermediate_filesystem, - ) { - Ok(cache) => Arc::new(cache), - Err(e) => { - tracing::warn!("create persistent cache failed {e:?}"); - Arc::new(MemoryCache) - } - } - } + ExperimentCacheOptions::Persistent(option) => Arc::new(PersistentCache::new( + compiler_path, + option, + compiler_option.clone(), + input_filesystem, + intermediate_filesystem, + )), } } diff --git a/crates/rspack_core/src/cache/persistent/mod.rs b/crates/rspack_core/src/cache/persistent/mod.rs index 031b0f60542..ed758d5a0a4 100644 --- a/crates/rspack_core/src/cache/persistent/mod.rs +++ b/crates/rspack_core/src/cache/persistent/mod.rs @@ -7,7 +7,8 @@ use std::{path::PathBuf, sync::Arc}; pub use cacheable_context::{CacheableContext, FromContext}; use occasion::MakeOccasion; -use rspack_fs::{FileSystem, IntermediateFileSystem, Result}; +use rspack_error::Result; +use rspack_fs::{FileSystem, IntermediateFileSystem}; use rspack_macros::rspack_version; use rspack_paths::ArcPath; use rustc_hash::FxHashSet as HashSet; @@ -42,39 +43,40 @@ impl PersistentCache { compiler_options: Arc, input_filesystem: Arc, intermediate_filesystem: Arc, - ) -> Result { + ) -> Self { let version = version::get_version( input_filesystem.clone(), &option.build_dependencies, vec![compiler_path, &option.version, rspack_version!()], - )?; + ); let storage = create_storage(option.storage.clone(), version, intermediate_filesystem); let context = Arc::new(CacheableContext { options: compiler_options, input_filesystem: input_filesystem.clone(), }); let make_occasion = MakeOccasion::new(storage.clone(), context); - Ok(Self { + Self { snapshot: Snapshot::new(option.snapshot.clone(), input_filesystem, storage.clone()), storage, make_occasion, - }) + } } } #[async_trait::async_trait] impl Cache for PersistentCache { - async fn before_compile(&self, compilation: &mut Compilation) { + async fn before_compile(&self, compilation: &mut Compilation) -> Result<()> { if compilation.modified_files.is_empty() && compilation.removed_files.is_empty() { // inject modified_files and removed_files - let (modified_paths, removed_paths) = self.snapshot.calc_modified_paths().await; + let (modified_paths, removed_paths) = self.snapshot.calc_modified_paths().await?; tracing::info!("cache::snapshot recovery {modified_paths:?} {removed_paths:?}",); compilation.modified_files = modified_paths; compilation.removed_files = removed_paths; } + Ok(()) } - fn after_compile(&self, compilation: &Compilation) { + async fn after_compile(&self, compilation: &Compilation) -> Result<()> { // TODO add a all_dependencies to collect dependencies let (_, file_added, file_removed) = compilation.file_dependencies(); let (_, context_added, context_removed) = compilation.context_dependencies(); @@ -103,24 +105,24 @@ impl Cache for PersistentCache { .remove(removed_paths.iter().map(|item| item.as_ref())); self .snapshot - .add(modified_paths.iter().map(|item| item.as_ref())); + .add(modified_paths.iter().map(|item| item.as_ref())) + .await; // TODO listen for storage finish in build mode let _ = self.storage.trigger_save(); + + Ok(()) } - async fn before_make(&self, make_artifact: &mut MakeArtifact) { + async fn before_make(&self, make_artifact: &mut MakeArtifact) -> Result<()> { if !make_artifact.initialized { - match self.make_occasion.recovery().await { - Ok(artifact) => *make_artifact = artifact, - Err(err) => { - tracing::warn!("recovery error with {err:?}") - } - } + *make_artifact = self.make_occasion.recovery().await?; } + Ok(()) } - fn after_make(&self, make_artifact: &MakeArtifact) { + async fn after_make(&self, make_artifact: &MakeArtifact) -> Result<()> { self.make_occasion.save(make_artifact); + Ok(()) } } diff --git a/crates/rspack_core/src/cache/persistent/occasion/make/dependencies.rs b/crates/rspack_core/src/cache/persistent/occasion/make/dependencies.rs index ef9367e4662..b546f928540 100644 --- a/crates/rspack_core/src/cache/persistent/occasion/make/dependencies.rs +++ b/crates/rspack_core/src/cache/persistent/occasion/make/dependencies.rs @@ -1,9 +1,8 @@ use std::sync::{Arc, Mutex}; use rayon::prelude::*; -use rspack_cacheable::{ - cacheable, from_bytes, to_bytes, with::Inline, DeserializeError, SerializeError, -}; +use rspack_cacheable::{cacheable, from_bytes, to_bytes, with::Inline}; +use rspack_error::Result; use rspack_paths::ArcPath; use rustc_hash::FxHashMap as HashMap; @@ -45,7 +44,7 @@ pub fn save_dependencies_info( missing_dependencies: &FileCounter, build_dependencies: &FileCounter, storage: &Arc, -) -> Result<(), SerializeError> { +) { let f = file_dependencies .updated_files_count_info() .map(|(path, count)| { @@ -98,37 +97,35 @@ pub fn save_dependencies_info( .chain(m) .chain(b) .par_bridge() - .try_for_each(|(dep_ref, count)| { - let dep_ref = to_bytes(&dep_ref, &())?; + .for_each(|(dep_ref, count)| { + let dep_ref = to_bytes(&dep_ref, &()).expect("should to bytes success"); if count == 0 { storage.remove(SCOPE, &dep_ref); } else { storage.set(SCOPE, dep_ref, count.to_ne_bytes().to_vec()); } - Ok(()) - }) + }); } pub async fn recovery_dependencies_info( storage: &Arc, -) -> Result<(FileCounter, FileCounter, FileCounter, FileCounter), DeserializeError> { +) -> Result<(FileCounter, FileCounter, FileCounter, FileCounter)> { let file_dep = Mutex::new(HashMap::default()); let context_dep = Mutex::new(HashMap::default()); let missing_dep = Mutex::new(HashMap::default()); let build_dep = Mutex::new(HashMap::default()); storage .load(SCOPE) - .await - .unwrap_or_default() + .await? .into_par_iter() - .try_for_each(|(k, v)| { + .for_each(|(k, v)| { let count = usize::from_ne_bytes( v.as_ref() .clone() .try_into() - .map_err(|_| DeserializeError::MessageError("deserialize count failed"))?, + .expect("should parse count success"), ); - let Dependency { r#type, path } = from_bytes(&k, &())?; + let Dependency { r#type, path } = from_bytes(&k, &()).expect("should from bytes success"); match r#type { DepType::File => file_dep .lock() @@ -147,8 +144,7 @@ pub async fn recovery_dependencies_info( .expect("should get build dep") .insert(path, count), }; - Ok(()) - })?; + }); Ok(( FileCounter::new(file_dep.into_inner().expect("into_inner should be success")), diff --git a/crates/rspack_core/src/cache/persistent/occasion/make/meta.rs b/crates/rspack_core/src/cache/persistent/occasion/make/meta.rs index 0de08dcf3ef..27822f31f26 100644 --- a/crates/rspack_core/src/cache/persistent/occasion/make/meta.rs +++ b/crates/rspack_core/src/cache/persistent/occasion/make/meta.rs @@ -1,9 +1,8 @@ use std::sync::{atomic::Ordering::Relaxed, Arc}; -use rspack_cacheable::{ - cacheable, from_bytes, to_bytes, with::Inline, DeserializeError, SerializeError, -}; +use rspack_cacheable::{cacheable, from_bytes, to_bytes, with::Inline}; use rspack_collections::IdentifierSet; +use rspack_error::Result; use rustc_hash::FxHashSet as HashSet; use super::Storage; @@ -34,23 +33,26 @@ pub fn save_meta( make_failed_dependencies: &HashSet, make_failed_module: &IdentifierSet, storage: &Arc, -) -> Result<(), SerializeError> { +) { let meta = MetaRef { make_failed_dependencies, make_failed_module, next_dependencies_id: DEPENDENCY_ID.load(Relaxed), }; - storage.set(SCOPE, "default".as_bytes().to_vec(), to_bytes(&meta, &())?); - Ok(()) + storage.set( + SCOPE, + "default".as_bytes().to_vec(), + to_bytes(&meta, &()).expect("should to bytes success"), + ); } pub async fn recovery_meta( storage: &Arc, -) -> Result<(HashSet, IdentifierSet), DeserializeError> { - let Some((_, value)) = storage.load(SCOPE).await.unwrap_or_default().pop() else { - return Err(DeserializeError::MessageError("can not get meta data")); +) -> Result<(HashSet, IdentifierSet)> { + let Some((_, value)) = storage.load(SCOPE).await?.pop() else { + return Ok(Default::default()); }; - let meta: Meta = from_bytes(&value, &())?; + let meta: Meta = from_bytes(&value, &()).expect("should from bytes success"); // TODO make dependency id to string like module id if DEPENDENCY_ID.load(Relaxed) < meta.next_dependencies_id { DEPENDENCY_ID.store(meta.next_dependencies_id, Relaxed); diff --git a/crates/rspack_core/src/cache/persistent/occasion/make/mod.rs b/crates/rspack_core/src/cache/persistent/occasion/make/mod.rs index c272559f8a9..ac1e4336494 100644 --- a/crates/rspack_core/src/cache/persistent/occasion/make/mod.rs +++ b/crates/rspack_core/src/cache/persistent/occasion/make/mod.rs @@ -4,7 +4,7 @@ mod module_graph; use std::sync::Arc; -use rspack_cacheable::DeserializeError; +use rspack_error::Result; use super::super::{cacheable_context::CacheableContext, Storage}; use crate::make::MakeArtifact; @@ -48,8 +48,7 @@ impl MakeOccasion { missing_dependencies, build_dependencies, &self.storage, - ) - .expect("should save dependencies success"); + ); module_graph::save_module_graph( module_graph_partial, @@ -59,14 +58,15 @@ impl MakeOccasion { &self.context, ); - meta::save_meta(make_failed_dependencies, make_failed_module, &self.storage) - .expect("should save make meta"); + meta::save_meta(make_failed_dependencies, make_failed_module, &self.storage); } #[tracing::instrument(name = "MakeOccasion::recovery", skip_all)] - pub async fn recovery(&self) -> Result { + pub async fn recovery(&self) -> Result { let mut artifact = MakeArtifact::default(); + // TODO can call recovery with multi thread + // TODO return DeserializeError not panic let (file_dependencies, context_dependencies, missing_dependencies, build_dependencies) = dependencies::recovery_dependencies_info(&self.storage).await?; artifact.file_dependencies = file_dependencies; diff --git a/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs b/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs index bb734303ffc..d5a9b3f40d3 100644 --- a/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs +++ b/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs @@ -4,9 +4,10 @@ use rayon::prelude::*; use rspack_cacheable::{ cacheable, from_bytes, to_bytes, with::{AsOption, AsTuple2, AsVec, Inline}, - DeserializeError, SerializeError, + SerializeError, }; use rspack_collections::IdentifierSet; +use rspack_error::Result; use rustc_hash::FxHashSet as HashSet; use super::Storage; @@ -125,11 +126,11 @@ pub fn save_module_graph( pub async fn recovery_module_graph( storage: &Arc, context: &CacheableContext, -) -> Result<(ModuleGraphPartial, HashSet), DeserializeError> { +) -> Result<(ModuleGraphPartial, HashSet)> { let mut need_check_dep = vec![]; let mut partial = ModuleGraphPartial::default(); let mut mg = ModuleGraph::new(vec![], Some(&mut partial)); - for (_, v) in storage.load(SCOPE).await.unwrap_or_default() { + for (_, v) in storage.load(SCOPE).await? { let mut node: Node = from_bytes(&v, context).expect("unexpected module graph deserialize failed"); for (dep, parent_block) in node.dependencies { diff --git a/crates/rspack_core/src/cache/persistent/snapshot/mod.rs b/crates/rspack_core/src/cache/persistent/snapshot/mod.rs index d0d3e353496..994ecf6d266 100644 --- a/crates/rspack_core/src/cache/persistent/snapshot/mod.rs +++ b/crates/rspack_core/src/cache/persistent/snapshot/mod.rs @@ -4,6 +4,7 @@ mod strategy; use std::{path::Path, sync::Arc}; use rspack_cacheable::{from_bytes, to_bytes}; +use rspack_error::Result; use rspack_fs::FileSystem; use rspack_paths::{ArcPath, AssertUtf8}; use rustc_hash::FxHashSet as HashSet; @@ -21,15 +22,10 @@ const SCOPE: &str = "snapshot"; #[derive(Debug)] pub struct Snapshot { options: SnapshotOptions, - // TODO - // 1. update compiler.input_file_system to async file system - // 2. update this fs to AsyncReadableFileSystem - // 3. update add/calc_modified_files to async fn fs: Arc, storage: Arc, } -// TODO remove all of `.expect()` to return error impl Snapshot { pub fn new(options: SnapshotOptions, fs: Arc, storage: Arc) -> Self { Self { @@ -39,24 +35,24 @@ impl Snapshot { } } - pub fn add(&self, paths: impl Iterator) { + pub async fn add(&self, paths: impl Iterator) { let default_strategy = StrategyHelper::compile_time(); let mut helper = StrategyHelper::new(self.fs.clone()); // TODO use multi thread // TODO merge package version file for path in paths { - // TODO check path exists let utf8_path = path.assert_utf8(); + // check path exists if self.fs.metadata(utf8_path).is_err() { continue; } - // TODO directory check all sub file + // TODO directory path should check all sub file let path_str = utf8_path.as_str(); if self.options.is_immutable_path(path_str) { continue; } if self.options.is_managed_path(path_str) { - if let Some(v) = helper.package_version(path) { + if let Some(v) = helper.package_version(path).await { self.storage.set( SCOPE, path.as_os_str().as_encoded_bytes().to_vec(), @@ -82,17 +78,17 @@ impl Snapshot { } } - pub async fn calc_modified_paths(&self) -> (HashSet, HashSet) { + pub async fn calc_modified_paths(&self) -> Result<(HashSet, HashSet)> { let mut helper = StrategyHelper::new(self.fs.clone()); let mut modified_path = HashSet::default(); let mut deleted_path = HashSet::default(); // TODO use multi thread - for (key, value) in self.storage.load(SCOPE).await.unwrap_or_default() { + for (key, value) in self.storage.load(SCOPE).await? { let path: ArcPath = Path::new(&*String::from_utf8_lossy(&key)).into(); let strategy: Strategy = from_bytes::(&value, &()).expect("should from bytes success"); - match helper.validate(&path, &strategy) { + match helper.validate(&path, &strategy).await { ValidateResult::Modified => { modified_path.insert(path); } @@ -102,7 +98,7 @@ impl Snapshot { ValidateResult::NoChanged => {} } } - (modified_path, deleted_path) + Ok((modified_path, deleted_path)) } } @@ -160,15 +156,17 @@ mod tests { let snapshot = Snapshot::new(options, fs.clone(), storage); - snapshot.add( - [ - p!("/file1"), - p!("/constant"), - p!("/node_modules/project/file1"), - p!("/node_modules/lib/file1"), - ] - .into_iter(), - ); + snapshot + .add( + [ + p!("/file1"), + p!("/constant"), + p!("/node_modules/project/file1"), + p!("/node_modules/lib/file1"), + ] + .into_iter(), + ) + .await; std::thread::sleep(std::time::Duration::from_millis(100)); fs.write("/file1".into(), "abcd".as_bytes()).await.unwrap(); fs.write("/constant".into(), "abcd".as_bytes()) @@ -181,7 +179,7 @@ mod tests { .await .unwrap(); - let (modified_paths, deleted_paths) = snapshot.calc_modified_paths().await; + let (modified_paths, deleted_paths) = snapshot.calc_modified_paths().await.unwrap(); assert!(deleted_paths.is_empty()); assert!(!modified_paths.contains(p!("/constant"))); assert!(modified_paths.contains(p!("/file1"))); @@ -194,8 +192,8 @@ mod tests { ) .await .unwrap(); - snapshot.add([p!("/file1")].into_iter()); - let (modified_paths, deleted_paths) = snapshot.calc_modified_paths().await; + snapshot.add([p!("/file1")].into_iter()).await; + let (modified_paths, deleted_paths) = snapshot.calc_modified_paths().await.unwrap(); assert!(deleted_paths.is_empty()); assert!(!modified_paths.contains(p!("/constant"))); assert!(!modified_paths.contains(p!("/file1"))); diff --git a/crates/rspack_core/src/cache/persistent/snapshot/strategy.rs b/crates/rspack_core/src/cache/persistent/snapshot/strategy.rs index 26a1b78d926..317e765d711 100644 --- a/crates/rspack_core/src/cache/persistent/snapshot/strategy.rs +++ b/crates/rspack_core/src/cache/persistent/snapshot/strategy.rs @@ -50,8 +50,8 @@ impl StrategyHelper { } /// get path file modified time - fn modified_time(&self, path: &Path) -> Option { - if let Ok(info) = self.fs.metadata(path.assert_utf8()) { + async fn modified_time(&self, path: &Path) -> Option { + if let Ok(info) = self.fs.stat(path.assert_utf8()).await { Some(info.mtime_ms) } else { None @@ -59,13 +59,18 @@ impl StrategyHelper { } /// get path file version in package.json - fn package_version_with_cache(&mut self, path: &Path) -> Option { + #[async_recursion::async_recursion] + async fn package_version_with_cache(&mut self, path: &Path) -> Option { if let Some(version) = self.package_version_cache.get(path) { return version.clone(); } let mut res = None; - if let Ok(content) = self.fs.read(&path.join("package.json").assert_utf8()) { + if let Ok(content) = self + .fs + .async_read(&path.join("package.json").assert_utf8()) + .await + { if let Ok(mut package_json) = serde_json::from_slice::>(&content) { @@ -77,7 +82,7 @@ impl StrategyHelper { if res.is_none() { if let Some(p) = path.parent() { - res = self.package_version_with_cache(p); + res = self.package_version_with_cache(p).await; } } @@ -94,17 +99,18 @@ impl StrategyHelper { Strategy::CompileTime(now) } /// get path file package version strategy - pub fn package_version(&mut self, path: &Path) -> Option { + pub async fn package_version(&mut self, path: &Path) -> Option { self .package_version_with_cache(path) + .await .map(Strategy::PackageVersion) } /// validate path file by target strategy - pub fn validate(&mut self, path: &Path, strategy: &Strategy) -> ValidateResult { + pub async fn validate(&mut self, path: &Path, strategy: &Strategy) -> ValidateResult { match strategy { Strategy::PackageVersion(version) => { - if let Some(ref cur_version) = self.package_version_with_cache(path) { + if let Some(ref cur_version) = self.package_version_with_cache(path).await { if cur_version == version { ValidateResult::NoChanged } else { @@ -115,7 +121,7 @@ impl StrategyHelper { } } Strategy::CompileTime(compile_time) => { - if let Some(ref modified_time) = self.modified_time(path) { + if let Some(ref modified_time) = self.modified_time(path).await { if modified_time > compile_time { ValidateResult::Modified } else { @@ -169,87 +175,99 @@ mod tests { let mut helper = StrategyHelper::new(fs.clone()); // modified_time assert_eq!( - helper.modified_time(Path::new("/file1")), + helper.modified_time(Path::new("/file1")).await, Some(fs.metadata("/file1".into()).unwrap().mtime_ms) ); - assert!(helper.modified_time(Path::new("/file2")).is_none()); + assert!(helper.modified_time(Path::new("/file2")).await.is_none()); // package_version_with_cache assert_eq!( helper .package_version_with_cache(Path::new("/packages/p1/file")) + .await .unwrap(), "1.0.0" ); assert_eq!( helper .package_version_with_cache(Path::new("/packages/p2/file")) + .await .unwrap(), "1.1.0" ); assert_eq!( helper .package_version_with_cache(Path::new("/packages/p2/dir1/dir2/dir3/file")) + .await .unwrap(), "1.1.0" ); assert!(helper .package_version_with_cache(Path::new("/file1")) + .await .is_none()); assert!(helper .package_version_with_cache(Path::new("/file2")) + .await .is_none()); // package_version assert_eq!( helper .package_version(Path::new("/packages/p1/file")) + .await .unwrap(), Strategy::PackageVersion("1.0.0".into()) ); assert_eq!( helper .package_version(Path::new("/packages/p2/file")) + .await .unwrap(), Strategy::PackageVersion("1.1.0".into()) ); assert_eq!( helper .package_version(Path::new("/packages/p2/dir1/dir2/dir3/file")) + .await .unwrap(), Strategy::PackageVersion("1.1.0".into()) ); - assert!(helper.package_version(Path::new("/file1")).is_none()); - assert!(helper.package_version(Path::new("/file2")).is_none()); + assert!(helper.package_version(Path::new("/file1")).await.is_none()); + assert!(helper.package_version(Path::new("/file2")).await.is_none()); // validate let now = StrategyHelper::compile_time(); assert!(matches!( - helper.validate(Path::new("/file1"), &now), + helper.validate(Path::new("/file1"), &now).await, ValidateResult::NoChanged )); std::thread::sleep(std::time::Duration::from_millis(100)); fs.write("/file1".into(), "abcd".as_bytes()).await.unwrap(); assert!(matches!( - helper.validate(Path::new("/file1"), &now), + helper.validate(Path::new("/file1"), &now).await, ValidateResult::Modified )); assert!(matches!( - helper.validate(Path::new("/file2"), &now), + helper.validate(Path::new("/file2"), &now).await, ValidateResult::Deleted )); let version = Strategy::PackageVersion("1.0.0".into()); assert!(matches!( - helper.validate(Path::new("/packages/p1/file1"), &version), + helper + .validate(Path::new("/packages/p1/file1"), &version) + .await, ValidateResult::NoChanged )); assert!(matches!( - helper.validate(Path::new("/packages/p2/file1"), &version), + helper + .validate(Path::new("/packages/p2/file1"), &version) + .await, ValidateResult::Modified )); assert!(matches!( - helper.validate(Path::new("/file2"), &version), + helper.validate(Path::new("/file2"), &version).await, ValidateResult::Deleted )); } diff --git a/crates/rspack_core/src/cache/persistent/version.rs b/crates/rspack_core/src/cache/persistent/version.rs index 5ea7aa79123..0f8938b1252 100644 --- a/crates/rspack_core/src/cache/persistent/version.rs +++ b/crates/rspack_core/src/cache/persistent/version.rs @@ -2,27 +2,28 @@ use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::PathBuf; use std::sync::Arc; -use rspack_fs::{Error, FileSystem, Result}; +use rspack_fs::FileSystem; use rspack_paths::AssertUtf8; pub fn get_version( fs: Arc, dependencies: &Vec, salt: Vec<&str>, -) -> Result { +) -> String { let mut hasher = DefaultHasher::new(); for dep in dependencies { let path = dep.clone().assert_utf8(); - let meta = fs.metadata(&path)?; + let meta = fs + .metadata(&path) + .unwrap_or_else(|_| panic!("Failed to get buildDependency({path}) metadata info.")); if !meta.is_file { - return Err(Error::Io(std::io::Error::new( - std::io::ErrorKind::Other, - format!("{path:?} is not a file"), - ))); + panic!("buildDependency({path}) is not a file."); } - let bytes = fs.read(&path)?; + let bytes = fs + .read(&path) + .unwrap_or_else(|_| panic!("Failed to read buildDependency({path}) content.")); bytes.hash(&mut hasher); } salt.hash(&mut hasher); - Ok(hex::encode(hasher.finish().to_ne_bytes())) + hex::encode(hasher.finish().to_ne_bytes()) } diff --git a/crates/rspack_core/src/compiler/hmr.rs b/crates/rspack_core/src/compiler/hmr.rs index 468cb036f2e..503989eaf02 100644 --- a/crates/rspack_core/src/compiler/hmr.rs +++ b/crates/rspack_core/src/compiler/hmr.rs @@ -181,14 +181,18 @@ impl Compiler { // Update `compilation` for each rebuild. // Make sure `thisCompilation` hook was called before any other hooks that leverage `JsCompilation`. fast_set(&mut self.compilation, new_compilation); - self.cache.before_compile(&mut self.compilation).await; + if let Err(err) = self.cache.before_compile(&mut self.compilation).await { + self.compilation.push_diagnostic(err.into()); + } self.compile().await?; self.old_cache.begin_idle(); } self.compile_done().await?; - self.cache.after_compile(&self.compilation); + if let Err(err) = self.cache.after_compile(&self.compilation).await { + self.compilation.push_diagnostic(err.into()); + } Ok(()) } diff --git a/crates/rspack_core/src/compiler/mod.rs b/crates/rspack_core/src/compiler/mod.rs index 230bebf328d..c5dc2642121 100644 --- a/crates/rspack_core/src/compiler/mod.rs +++ b/crates/rspack_core/src/compiler/mod.rs @@ -185,12 +185,16 @@ impl Compiler { self.output_filesystem.clone(), ), ); - self.cache.before_compile(&mut self.compilation).await; + if let Err(err) = self.cache.before_compile(&mut self.compilation).await { + self.compilation.push_diagnostic(err.into()); + } self.compile().await?; self.old_cache.begin_idle(); self.compile_done().await?; - self.cache.after_compile(&self.compilation); + if let Err(err) = self.cache.after_compile(&self.compilation).await { + self.compilation.push_diagnostic(err.into()); + } Ok(()) } @@ -218,10 +222,13 @@ impl Compiler { let logger = self.compilation.get_logger("rspack.Compiler"); let make_start = logger.time("make"); let make_hook_start = logger.time("make hook"); - self + if let Err(err) = self .cache .before_make(&mut self.compilation.make_artifact) - .await; + .await + { + self.compilation.push_diagnostic(err.into()); + } if let Some(e) = self .plugin_driver .compiler_hooks @@ -247,7 +254,9 @@ impl Compiler { let start = logger.time("finish compilation"); self.compilation.finish(self.plugin_driver.clone()).await?; - self.cache.after_make(&self.compilation.make_artifact); + if let Err(err) = self.cache.after_make(&self.compilation.make_artifact).await { + self.compilation.push_diagnostic(err.into()); + } logger.time_end(start); let start = logger.time("seal compilation"); self.compilation.seal(self.plugin_driver.clone()).await?;