@@ -131,49 +131,99 @@ async fn inner_impl(compilation: &mut Compilation) -> Result<()> {
131
131
} )
132
132
. collect ( ) ;
133
133
134
- let ordered_hashes = OrderedHashesBuilder :: new ( & hash_to_asset_names, & assets_data) . build ( ) ;
134
+ let ( ordered_hashes, mut hash_dependencies) =
135
+ OrderedHashesBuilder :: new ( & hash_to_asset_names, & assets_data) . build ( ) ;
136
+ let mut ordered_hashes_iter = ordered_hashes. iter ( ) ;
137
+
135
138
logger. time_end ( start) ;
136
139
137
140
let start = logger. time ( "old hash to new hash" ) ;
138
141
let mut hash_to_new_hash = HashMap :: default ( ) ;
139
142
140
143
let hooks = RealContentHashPlugin :: get_compilation_hooks ( compilation. id ( ) ) ;
141
- for old_hash in & ordered_hashes {
142
- if let Some ( asset_names) = hash_to_asset_names. get_mut ( old_hash. as_str ( ) ) {
143
- asset_names. sort ( ) ;
144
- let mut asset_contents: Vec < _ > = asset_names
145
- . par_iter ( )
146
- . filter_map ( |name| assets_data. get ( name) )
147
- . map ( |data| {
148
- data
149
- . compute_new_source (
150
- data. own_hashes . contains ( old_hash) ,
151
- & hash_to_new_hash,
152
- & hash_regexp,
153
- )
154
- . clone ( )
155
- } )
156
- . collect ( ) ;
157
- asset_contents. dedup ( ) ;
158
- let updated_hash = hooks
159
- . update_hash
160
- . call ( compilation, & asset_contents, old_hash)
161
- . await ?;
162
-
163
- let new_hash = if let Some ( new_hash) = updated_hash {
164
- new_hash
165
- } else {
166
- let mut hasher = RspackHash :: from ( & compilation. options . output ) ;
167
- for asset_content in asset_contents {
168
- hasher. write ( & asset_content. buffer ( ) ) ;
169
- }
170
- let new_hash = hasher. digest ( & compilation. options . output . hash_digest ) ;
171
- let new_hash = new_hash. rendered ( old_hash. len ( ) ) . to_string ( ) ;
172
- new_hash
144
+
145
+ let mut computed_hashes = HashSet :: default ( ) ;
146
+ let mut top_task = ordered_hashes_iter. next ( ) ;
147
+
148
+ loop {
149
+ let Some ( top) = top_task else {
150
+ break ;
151
+ } ;
152
+ let mut batch = vec ! [ top] ;
153
+ top_task = None ;
154
+
155
+ for hash in ordered_hashes_iter. by_ref ( ) {
156
+ let Some ( dependencies) = hash_dependencies. remove ( hash. as_str ( ) ) else {
157
+ top_task = Some ( hash) ;
158
+ break ;
173
159
} ;
174
- hash_to_new_hash. insert ( old_hash, new_hash) ;
160
+ if dependencies. iter ( ) . all ( |dep| computed_hashes. contains ( dep) ) {
161
+ batch. push ( hash) ;
162
+ } else {
163
+ top_task = Some ( hash) ;
164
+ break ;
165
+ }
166
+ }
167
+
168
+ let batch_source_tasks = batch
169
+ . iter ( )
170
+ . filter_map ( |hash| {
171
+ let assets_names = hash_to_asset_names. get ( hash. as_str ( ) ) ?;
172
+ let tasks = assets_names
173
+ . iter ( )
174
+ . filter_map ( |name| {
175
+ let data = assets_data. get ( name) ?;
176
+ Some ( ( hash. as_str ( ) , * name, data) )
177
+ } )
178
+ . collect :: < Vec < _ > > ( ) ;
179
+ Some ( tasks)
180
+ } )
181
+ . flatten ( )
182
+ . collect :: < Vec < _ > > ( ) ;
183
+
184
+ let mut batch_sources = batch_source_tasks
185
+ . into_par_iter ( )
186
+ . map ( |( hash, name, data) | {
187
+ let new_source = data. compute_new_source (
188
+ data. own_hashes . contains ( hash) ,
189
+ & hash_to_new_hash,
190
+ & hash_regexp,
191
+ ) ;
192
+ ( ( hash, name) , new_source)
193
+ } )
194
+ . collect :: < HashMap < _ , _ > > ( ) ;
195
+
196
+ for old_hash in batch. iter ( ) {
197
+ if let Some ( asset_names) = hash_to_asset_names. get_mut ( old_hash. as_str ( ) ) {
198
+ asset_names. sort ( ) ;
199
+ let mut asset_contents = asset_names
200
+ . iter ( )
201
+ . filter_map ( |name| batch_sources. remove ( & ( old_hash. as_str ( ) , name) ) )
202
+ . collect :: < Vec < _ > > ( ) ;
203
+ asset_contents. dedup ( ) ;
204
+ let updated_hash = hooks
205
+ . update_hash
206
+ . call ( compilation, & asset_contents, old_hash)
207
+ . await ?;
208
+
209
+ let new_hash = if let Some ( new_hash) = updated_hash {
210
+ new_hash
211
+ } else {
212
+ let mut hasher = RspackHash :: from ( & compilation. options . output ) ;
213
+ for asset_content in asset_contents {
214
+ hasher. write ( & asset_content. buffer ( ) ) ;
215
+ }
216
+ let new_hash = hasher. digest ( & compilation. options . output . hash_digest ) ;
217
+ let new_hash = new_hash. rendered ( old_hash. len ( ) ) . to_string ( ) ;
218
+ new_hash
219
+ } ;
220
+ hash_to_new_hash. insert ( old_hash, new_hash) ;
221
+ }
175
222
}
223
+
224
+ computed_hashes. extend ( batch) ;
176
225
}
226
+
177
227
logger. time_end ( start) ;
178
228
179
229
let start = logger. time ( "collect hash updates" ) ;
@@ -193,7 +243,7 @@ async fn inner_impl(compilation: &mut Compilation) -> Result<()> {
193
243
} )
194
244
. into_owned ( ) ;
195
245
let new_name = ( name != new_name) . then_some ( new_name) ;
196
- Some ( ( name. to_owned ( ) , new_source. clone ( ) , new_name) )
246
+ Some ( ( name. to_owned ( ) , new_source, new_name) )
197
247
} )
198
248
. collect ( ) ;
199
249
logger. time_end ( start) ;
@@ -279,7 +329,7 @@ impl AssetData {
279
329
without_own : bool ,
280
330
hash_to_new_hash : & HashMap < & str , String > ,
281
331
hash_regexp : & Regex ,
282
- ) -> & BoxSource {
332
+ ) -> BoxSource {
283
333
( if without_own {
284
334
& self . new_source_without_own
285
335
} else {
@@ -309,6 +359,7 @@ impl AssetData {
309
359
}
310
360
self . old_source . clone ( )
311
361
} )
362
+ . clone ( )
312
363
}
313
364
}
314
365
@@ -328,12 +379,29 @@ impl<'a> OrderedHashesBuilder<'a> {
328
379
}
329
380
}
330
381
331
- pub fn build ( & self ) -> IndexSet < String > {
382
+ pub fn build ( & self ) -> ( IndexSet < String > , HashMap < String , HashSet < String > > ) {
332
383
let mut ordered_hashes = IndexSet :: default ( ) ;
384
+ let mut hash_dependencies = HashMap :: default ( ) ;
333
385
for hash in self . hash_to_asset_names . keys ( ) {
334
- self . add_to_ordered_hashes ( hash, & mut ordered_hashes, & mut HashSet :: default ( ) ) ;
386
+ self . add_to_ordered_hashes (
387
+ hash,
388
+ & mut ordered_hashes,
389
+ & mut HashSet :: default ( ) ,
390
+ & mut hash_dependencies,
391
+ ) ;
335
392
}
336
- ordered_hashes
393
+ (
394
+ ordered_hashes,
395
+ hash_dependencies
396
+ . into_iter ( )
397
+ . map ( |( k, v) | {
398
+ (
399
+ k. to_string ( ) ,
400
+ v. into_iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ,
401
+ )
402
+ } )
403
+ . collect ( ) ,
404
+ )
337
405
}
338
406
}
339
407
@@ -364,8 +432,12 @@ impl OrderedHashesBuilder<'_> {
364
432
hash : & ' b str ,
365
433
ordered_hashes : & mut IndexSet < String > ,
366
434
stack : & mut HashSet < & ' b str > ,
435
+ hash_dependencies : & mut HashMap < & ' b str , HashSet < & ' b str > > ,
367
436
) {
368
- let deps = self . get_hash_dependencies ( hash) ;
437
+ let deps = hash_dependencies
438
+ . entry ( hash)
439
+ . or_insert_with ( || self . get_hash_dependencies ( hash) )
440
+ . clone ( ) ;
369
441
stack. insert ( hash) ;
370
442
for dep in deps {
371
443
if ordered_hashes. contains ( dep) {
@@ -376,7 +448,7 @@ impl OrderedHashesBuilder<'_> {
376
448
// so there shouldn't have circular hash dependency between chunks
377
449
panic ! ( "RealContentHashPlugin: circular hash dependency" ) ;
378
450
}
379
- self . add_to_ordered_hashes ( dep, ordered_hashes, stack) ;
451
+ self . add_to_ordered_hashes ( dep, ordered_hashes, stack, hash_dependencies ) ;
380
452
}
381
453
ordered_hashes. insert ( hash. to_string ( ) ) ;
382
454
stack. remove ( hash) ;
0 commit comments