11use std:: { collections:: VecDeque , path:: PathBuf , sync:: Arc } ;
22
3+ use rspack_error:: Result ;
34use rspack_fs:: ReadableFileSystem ;
45use rspack_paths:: { AssertUtf8 , InternedPath , InternedPathSet } ;
56
6- use super :: { Snapshot , SnapshotEntry } ;
7+ use super :: { FileSystemInfo , Snapshot , SnapshotValidationResult } ;
78use crate :: {
89 CompilationLogger ,
910 cache:: persistent:: build_dependencies:: { Helper , is_node_package_path} ,
@@ -22,6 +23,14 @@ pub enum BuildDepsValidationResult {
2223 } ,
2324}
2425
26+ #[ derive( Debug , Default ) ]
27+ pub struct ResolvedBuildDependencies {
28+ pub ( crate ) dependencies : InternedPathSet ,
29+ pub ( crate ) files : InternedPathSet ,
30+ pub ( crate ) contexts : InternedPathSet ,
31+ pub ( crate ) missing : InternedPathSet ,
32+ }
33+
2534/// Build dependencies manager.
2635#[ derive( Debug ) ]
2736pub struct BuildDeps {
@@ -51,21 +60,35 @@ impl BuildDeps {
5160 ///
5261 /// For performance reasons, recursive searches stop at dependencies in
5362 /// `node_modules`.
63+ ///
64+ /// See webpack's build dependency resolution implementation:
65+ /// https://github.com/webpack/webpack/blob/ce97d583e1cd8f3e47b70737de72e91b567a8497/lib/FileSystemInfo.js#L1873-L2523
5466 pub async fn resolve_dependencies (
5567 & mut self ,
5668 current : & InternedPathSet ,
5769 paths : impl Iterator < Item = InternedPath > ,
58- ) -> InternedPathSet {
70+ ) -> ResolvedBuildDependencies {
5971 let mut helper = Helper :: new ( self . fs . clone ( ) , self . logger . clone ( ) ) ;
60- let mut added = InternedPathSet :: default ( ) ;
72+ let mut resolved = ResolvedBuildDependencies :: default ( ) ;
6173 let mut queue = VecDeque :: new ( ) ;
6274 queue. extend ( self . pending . iter ( ) . cloned ( ) ) ;
6375 queue. extend ( paths) ;
6476
6577 while let Some ( dependency) = queue. pop_front ( ) {
66- if current. contains ( & dependency) || !added . insert ( dependency. clone ( ) ) {
78+ if current. contains ( & dependency) || !resolved . dependencies . insert ( dependency. clone ( ) ) {
6779 continue ;
6880 }
81+ match self . fs . metadata ( dependency. assert_utf8 ( ) ) . await {
82+ Ok ( metadata) if metadata. is_directory => {
83+ resolved. contexts . insert ( dependency. clone ( ) ) ;
84+ }
85+ Ok ( _) => {
86+ resolved. files . insert ( dependency. clone ( ) ) ;
87+ }
88+ Err ( _) => {
89+ resolved. missing . insert ( dependency. clone ( ) ) ;
90+ }
91+ }
6992 if is_node_package_path ( & dependency) {
7093 continue ;
7194 }
@@ -79,25 +102,44 @@ impl BuildDeps {
79102 }
80103
81104 self . pending . clear ( ) ;
82- added
105+ resolved
83106 }
84107
85108 /// Validate build dependencies.
86109 ///
87110 /// If any build dependency changed, this method returns an invalid result.
88111 pub async fn validate_snapshot (
89112 & self ,
113+ file_system_info : & FileSystemInfo ,
90114 snapshot : & Snapshot ,
91- entries : & [ SnapshotEntry ] ,
115+ dependencies : & InternedPathSet ,
92116 tracked_files : usize ,
93- ) -> BuildDepsValidationResult {
94- let ( modified_files, removed_files) = snapshot. calc_modified_paths ( entries) . await ;
95- if !modified_files. is_empty ( ) || !removed_files. is_empty ( ) {
96- return BuildDepsValidationResult :: Invalid {
97- modified_files,
117+ ) -> Result < BuildDepsValidationResult > {
118+ let validation = file_system_info. check_snapshot_valid ( snapshot) . await ?;
119+ let pending = self
120+ . pending
121+ . iter ( )
122+ . filter ( |path| !dependencies. contains ( * path) )
123+ . cloned ( )
124+ . collect :: < InternedPathSet > ( ) ;
125+ match validation {
126+ SnapshotValidationResult :: Valid if pending. is_empty ( ) => {
127+ Ok ( BuildDepsValidationResult :: Valid { tracked_files } )
128+ }
129+ SnapshotValidationResult :: Valid => Ok ( BuildDepsValidationResult :: Invalid {
130+ modified_files : pending,
131+ removed_files : Default :: default ( ) ,
132+ } ) ,
133+ SnapshotValidationResult :: Invalid {
134+ mut modified_files,
98135 removed_files,
99- } ;
136+ } => {
137+ modified_files. extend ( pending) ;
138+ Ok ( BuildDepsValidationResult :: Invalid {
139+ modified_files,
140+ removed_files,
141+ } )
142+ }
100143 }
101- BuildDepsValidationResult :: Valid { tracked_files }
102144 }
103145}
0 commit comments