1
- use std:: {
2
- borrow:: Cow ,
3
- hash:: BuildHasherDefault ,
4
- iter:: once,
5
- sync:: { atomic:: AtomicU32 , Arc } ,
6
- } ;
1
+ use std:: { borrow:: Cow , hash:: BuildHasherDefault , iter:: once, sync:: atomic:: AtomicU32 } ;
7
2
8
3
use indexmap:: IndexSet ;
9
4
use rayon:: prelude:: * ;
10
5
use rspack_collections:: {
11
- DatabaseItem , IdentifierDashMap , IdentifierHasher , IdentifierIndexMap , IdentifierIndexSet ,
12
- IdentifierMap , IdentifierSet , Ukey , UkeyMap ,
6
+ DatabaseItem , IdentifierHasher , IdentifierIndexMap , IdentifierIndexSet , IdentifierMap ,
7
+ IdentifierSet , Ukey , UkeyMap ,
13
8
} ;
14
9
use rspack_error:: { error, Diagnostic , Result } ;
15
10
use rustc_hash:: { FxHashMap as HashMap , FxHashSet as HashSet } ;
@@ -28,7 +23,7 @@ use crate::{
28
23
29
24
type ModuleDeps = HashMap <
30
25
RuntimeSpec ,
31
- IdentifierDashMap < Arc < ( Vec < ModuleIdentifier > , Vec < AsyncDependenciesBlockIdentifier > ) > > ,
26
+ IdentifierMap < ( Vec < ModuleIdentifier > , Vec < AsyncDependenciesBlockIdentifier > ) > ,
32
27
> ;
33
28
34
29
static NEXT_CACHE_UKEY : AtomicU32 = AtomicU32 :: new ( 0 ) ;
@@ -194,7 +189,6 @@ impl CreateChunkRoot {
194
189
195
190
fn create ( & self , splitter : & CodeSplitter , compilation : & Compilation ) -> Vec < ChunkDesc > {
196
191
let module_graph = compilation. get_module_graph ( ) ;
197
- let module_graph_cache = & compilation. module_graph_cache_artifact ;
198
192
199
193
match self {
200
194
CreateChunkRoot :: Entry ( entry, data, runtime) => {
@@ -235,7 +229,7 @@ impl CreateChunkRoot {
235
229
)
236
230
. filter_map ( |dep_id| module_graph. module_identifier_by_dependency_id ( dep_id) )
237
231
{
238
- splitter. fill_chunk_modules ( * m, runtime, & module_graph, module_graph_cache , & mut ctx) ;
232
+ splitter. fill_chunk_modules ( * m, runtime, & module_graph, & mut ctx) ;
239
233
}
240
234
241
235
vec ! [ ChunkDesc :: Entry ( Box :: new( EntryChunkDesc {
@@ -289,7 +283,7 @@ impl CreateChunkRoot {
289
283
continue ;
290
284
} ;
291
285
292
- splitter. fill_chunk_modules ( * m, runtime, & module_graph, module_graph_cache , & mut ctx) ;
286
+ splitter. fill_chunk_modules ( * m, runtime, & module_graph, & mut ctx) ;
293
287
}
294
288
295
289
if let Some ( group_option) = block. get_group_options ( )
@@ -383,7 +377,7 @@ impl CodeSplitter {
383
377
384
378
fn invalidate_outgoing_cache ( & mut self , module : ModuleIdentifier ) {
385
379
// refresh module traversal result in the last compilation
386
- for map in self . module_deps . values ( ) {
380
+ for map in self . module_deps . values_mut ( ) {
387
381
map. remove ( & module) ;
388
382
}
389
383
}
@@ -428,6 +422,10 @@ impl CodeSplitter {
428
422
fn analyze_module_graph (
429
423
& mut self ,
430
424
compilation : & mut Compilation ,
425
+ prepared_outgoings : & IdentifierMap < (
426
+ IdentifierIndexMap < Vec < ModuleGraphConnection > > ,
427
+ Vec < AsyncDependenciesBlockIdentifier > ,
428
+ ) > ,
431
429
) -> Result < Vec < CreateChunkRoot > > {
432
430
// determine runtime and chunkLoading
433
431
let mut entry_runtime: std:: collections:: HashMap < & str , RuntimeSpec , rustc_hash:: FxBuildHasher > =
@@ -500,12 +498,15 @@ impl CodeSplitter {
500
498
continue ;
501
499
}
502
500
503
- let guard =
504
- self . outgoings_modules ( & module, runtime. as_ref ( ) , & module_graph, module_graph_cache) ;
505
- let ( modules, blocks) = guard. as_ref ( ) ;
506
- let blocks = blocks. clone ( ) ;
501
+ let ( modules, blocks) = self . outgoings_modules (
502
+ & module,
503
+ runtime. as_ref ( ) ,
504
+ & module_graph,
505
+ module_graph_cache,
506
+ prepared_outgoings,
507
+ ) ;
507
508
for m in modules {
508
- stack. push ( ( * m, runtime. clone ( ) , chunk_loading) ) ;
509
+ stack. push ( ( m, runtime. clone ( ) , chunk_loading) ) ;
509
510
}
510
511
511
512
for block_id in blocks {
@@ -742,40 +743,41 @@ impl CodeSplitter {
742
743
. unwrap_or_else ( || panic ! ( "should have module ordinal: {m}" ) )
743
744
}
744
745
745
- pub fn outgoings_modules (
746
+ pub fn get_outgoings_modules (
746
747
& self ,
747
748
module : & ModuleIdentifier ,
748
749
runtime : & RuntimeSpec ,
749
- module_graph : & ModuleGraph ,
750
- module_graph_cache : & ModuleGraphCacheArtifact ,
751
- ) -> Arc < ( Vec < ModuleIdentifier > , Vec < AsyncDependenciesBlockIdentifier > ) > {
750
+ ) -> Option < ( Vec < ModuleIdentifier > , Vec < AsyncDependenciesBlockIdentifier > ) > {
752
751
let module_map = self . module_deps . get ( runtime) . expect ( "should have value" ) ;
752
+ module_map. get ( module) . cloned ( )
753
+ }
753
754
754
- let guard = module_map. get ( module) ;
755
- if let Some ( ref_value) = guard {
756
- return ref_value. clone ( ) ;
755
+ pub fn outgoings_modules (
756
+ & mut self ,
757
+ module : & ModuleIdentifier ,
758
+ runtime : & RuntimeSpec ,
759
+ module_graph : & ModuleGraph ,
760
+ module_graph_cache : & ModuleGraphCacheArtifact ,
761
+ prepared_outgoings : & IdentifierMap < (
762
+ IdentifierIndexMap < Vec < ModuleGraphConnection > > ,
763
+ Vec < AsyncDependenciesBlockIdentifier > ,
764
+ ) > ,
765
+ ) -> ( Vec < ModuleIdentifier > , Vec < AsyncDependenciesBlockIdentifier > ) {
766
+ if let Some ( ref_value) = self
767
+ . module_deps
768
+ . get_mut ( runtime)
769
+ . expect ( "should have value" )
770
+ . get ( module)
771
+ {
772
+ return ( ref_value. 0 . clone ( ) , ref_value. 1 . clone ( ) ) ;
757
773
}
758
774
759
- let mut outgoings = IdentifierIndexMap :: < Vec < & ModuleGraphConnection > > :: default ( ) ;
760
- let m = module_graph
761
- . module_by_identifier ( module)
762
- . expect ( "should have module" ) ;
763
-
764
- m. get_dependencies ( )
765
- . iter ( )
766
- . filter ( |dep_id| {
767
- module_graph
768
- . dependency_by_id ( dep_id)
769
- . expect ( "should have dep" )
770
- . as_module_dependency ( )
771
- . is_none_or ( |module_dep| !module_dep. weak ( ) )
772
- } )
773
- . filter_map ( |dep| module_graph. connection_by_dependency_id ( dep) )
774
- . map ( |conn| ( conn. module_identifier ( ) , conn) )
775
- . for_each ( |( module, conn) | outgoings. entry ( * module) . or_default ( ) . push ( conn) ) ;
775
+ let ( outgoings, blocks) = prepared_outgoings
776
+ . get ( module)
777
+ . expect ( "should have outgoings" ) ;
776
778
777
779
let mut modules = IdentifierIndexSet :: default ( ) ;
778
- let mut blocks = m . get_blocks ( ) . to_vec ( ) ;
780
+ let mut blocks = blocks . clone ( ) ;
779
781
780
782
' outer: for ( m, conns) in outgoings. iter ( ) {
781
783
for conn in conns {
@@ -786,19 +788,29 @@ impl CodeSplitter {
786
788
continue ' outer;
787
789
}
788
790
crate :: ConnectionState :: TransitiveOnly => {
789
- let transitive = self . outgoings_modules ( m, runtime, module_graph, module_graph_cache) ;
790
- let ( extra_modules, extra_blocks) = transitive. as_ref ( ) ;
791
- modules. extend ( extra_modules. iter ( ) . copied ( ) ) ;
792
- blocks. extend ( extra_blocks. iter ( ) . copied ( ) ) ;
791
+ let ( extra_modules, extra_blocks) = self . outgoings_modules (
792
+ m,
793
+ runtime,
794
+ module_graph,
795
+ module_graph_cache,
796
+ prepared_outgoings,
797
+ ) ;
798
+ modules. extend ( extra_modules) ;
799
+ blocks. extend ( extra_blocks) ;
793
800
}
794
801
crate :: ConnectionState :: Active ( false ) => { }
795
802
crate :: ConnectionState :: CircularConnection => { }
796
803
}
797
804
}
798
805
}
799
806
800
- module_map. insert ( * module, Arc :: new ( ( modules. into_iter ( ) . collect ( ) , blocks) ) ) ;
801
- module_map. get ( module) . expect ( "have value" ) . clone ( )
807
+ let module_map = self
808
+ . module_deps
809
+ . get_mut ( runtime)
810
+ . expect ( "should have value" ) ;
811
+ let modules = modules. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
812
+ module_map. insert ( * module, ( modules. clone ( ) , blocks. clone ( ) ) ) ;
813
+ ( modules, blocks)
802
814
}
803
815
804
816
// insert static dependencies into a set
@@ -807,7 +819,6 @@ impl CodeSplitter {
807
819
target_module : ModuleIdentifier ,
808
820
runtime : & RuntimeSpec ,
809
821
module_graph : & ModuleGraph ,
810
- module_graph_cache : & ModuleGraphCacheArtifact ,
811
822
ctx : & mut FillCtx ,
812
823
) {
813
824
enum Task {
@@ -843,13 +854,16 @@ impl CodeSplitter {
843
854
value
844
855
} ) ;
845
856
846
- let guard =
847
- self . outgoings_modules ( & target_module, runtime, module_graph, module_graph_cache) ;
848
- let ( outgoing_modules, blocks) = guard. as_ref ( ) ;
849
- let mut outgoing_modules = outgoing_modules. clone ( ) ;
857
+ let Some ( ( mut outgoing_modules, blocks) ) =
858
+ self . get_outgoings_modules ( & target_module, runtime)
859
+ else {
860
+ // not exists when error occurs
861
+ // just skip it and the errors will be reported in stats
862
+ continue ;
863
+ } ;
850
864
851
865
if ctx. chunk_loading {
852
- ctx. out_goings . extend ( blocks. clone ( ) ) ;
866
+ ctx. out_goings . extend ( blocks) ;
853
867
} else {
854
868
let modules = blocks
855
869
. iter ( )
@@ -926,8 +940,6 @@ impl CodeSplitter {
926
940
}
927
941
928
942
let mut visited = HashSet :: default ( ) ;
929
- let module_graph = compilation. get_module_graph ( ) ;
930
- let module_graph_cache = & compilation. module_graph_cache_artifact ;
931
943
932
944
queue. reverse ( ) ;
933
945
@@ -971,8 +983,11 @@ impl CodeSplitter {
971
983
if !self . module_deps . contains_key ( runtime) {
972
984
self . module_deps . insert ( runtime. clone ( ) , Default :: default ( ) ) ;
973
985
}
974
- let guard = self . outgoings_modules ( & m, runtime, & module_graph, module_graph_cache) ;
975
- let ( modules, blocks) = guard. as_ref ( ) ;
986
+ let Some ( ( modules, blocks) ) = self . get_outgoings_modules ( & m, runtime) else {
987
+ // not exists when error occurs
988
+ // just skip it and the errors will be reported in stats
989
+ continue ;
990
+ } ;
976
991
977
992
for m in modules. iter ( ) . rev ( ) {
978
993
queue. push ( Task :: Enter ( ( * m, runtime) ) ) ;
@@ -981,9 +996,9 @@ impl CodeSplitter {
981
996
for block_id in blocks {
982
997
if let Some ( chunk_group) = compilation
983
998
. chunk_graph
984
- . get_block_chunk_group ( block_id, & compilation. chunk_group_by_ukey )
999
+ . get_block_chunk_group ( & block_id, & compilation. chunk_group_by_ukey )
985
1000
{
986
- queue_delay. push ( Task :: Group ( chunk_group. ukey ( ) , * block_id) ) ;
1001
+ queue_delay. push ( Task :: Group ( chunk_group. ukey ( ) , block_id) ) ;
987
1002
}
988
1003
}
989
1004
}
@@ -1033,10 +1048,47 @@ impl CodeSplitter {
1033
1048
ukey
1034
1049
}
1035
1050
1051
+ fn prepare_outgoings (
1052
+ & self ,
1053
+ compilation : & Compilation ,
1054
+ ) -> IdentifierMap < (
1055
+ IdentifierIndexMap < Vec < ModuleGraphConnection > > ,
1056
+ Vec < AsyncDependenciesBlockIdentifier > ,
1057
+ ) > {
1058
+ let module_graph = compilation. get_module_graph ( ) ;
1059
+ let modules = module_graph. modules ( ) . keys ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
1060
+ modules
1061
+ . into_par_iter ( )
1062
+ . map ( |mid| {
1063
+ let mut outgoings = IdentifierIndexMap :: < Vec < ModuleGraphConnection > > :: default ( ) ;
1064
+ let m = module_graph
1065
+ . module_by_identifier ( & mid)
1066
+ . expect ( "should have module" ) ;
1067
+ let blocks = m. get_blocks ( ) . to_vec ( ) ;
1068
+ m. get_dependencies ( )
1069
+ . iter ( )
1070
+ . filter ( |dep_id| {
1071
+ module_graph
1072
+ . dependency_by_id ( dep_id)
1073
+ . expect ( "should have dep" )
1074
+ . as_module_dependency ( )
1075
+ . is_none_or ( |module_dep| !module_dep. weak ( ) )
1076
+ } )
1077
+ . filter_map ( |dep| module_graph. connection_by_dependency_id ( dep) )
1078
+ . map ( |conn| ( conn. module_identifier ( ) , conn) )
1079
+ . for_each ( |( module, conn) | outgoings. entry ( * module) . or_default ( ) . push ( conn. clone ( ) ) ) ;
1080
+
1081
+ ( mid, ( outgoings, blocks) )
1082
+ } )
1083
+ . collect :: < IdentifierMap < _ > > ( )
1084
+ }
1085
+
1036
1086
fn create_chunks ( & mut self , compilation : & mut Compilation ) -> Result < ( ) > {
1037
1087
let mut errors = vec ! [ ] ;
1038
1088
1039
- let mut roots = self . analyze_module_graph ( compilation) ?;
1089
+ let outgoings = self . prepare_outgoings ( compilation) ;
1090
+
1091
+ let mut roots = self . analyze_module_graph ( compilation, & outgoings) ?;
1040
1092
1041
1093
let enable_incremental: bool = compilation
1042
1094
. incremental
@@ -1102,6 +1154,22 @@ impl CodeSplitter {
1102
1154
let mut async_entrypoints = HashSet :: default ( ) ;
1103
1155
let mut entrypoints = HashMap :: default ( ) ;
1104
1156
let mut skipped = HashSet :: < usize > :: default ( ) ;
1157
+ let outgoings = {
1158
+ let mg = compilation. get_module_graph ( ) ;
1159
+ let all_modules = mg. modules ( ) ;
1160
+ all_modules
1161
+ . keys ( )
1162
+ . par_bridge ( )
1163
+ . map ( |mid| {
1164
+ (
1165
+ * mid,
1166
+ mg. get_outgoing_connections ( mid)
1167
+ . cloned ( )
1168
+ . collect :: < Vec < _ > > ( ) ,
1169
+ )
1170
+ } )
1171
+ . collect :: < IdentifierMap < _ > > ( )
1172
+ } ;
1105
1173
1106
1174
for ( idx, ( reuse, cache) ) in finalize_result. chunks . into_iter ( ) . enumerate ( ) {
1107
1175
let chunk_desc = cache. chunk_desc ;
@@ -1283,11 +1351,7 @@ Or do you want to use the entrypoints '{name}' and '{entry_runtime}' independent
1283
1351
1284
1352
if initial {
1285
1353
let mut assign_depths_map = IdentifierMap :: default ( ) ;
1286
- assign_depths (
1287
- & mut assign_depths_map,
1288
- & compilation. get_module_graph ( ) ,
1289
- entry_modules. iter ( ) ,
1290
- ) ;
1354
+ assign_depths ( & mut assign_depths_map, & entry_modules, & outgoings) ;
1291
1355
let mut module_graph = compilation. get_module_graph_mut ( ) ;
1292
1356
for ( m, depth) in assign_depths_map {
1293
1357
module_graph. set_depth_if_lower ( & m, depth) ;
0 commit comments