@@ -17,7 +17,7 @@ use rspack_identifier::{Identifiable, Identifier};
1717use rspack_macros:: impl_source_map_config;
1818use rspack_regex:: RspackRegex ;
1919use rspack_sources:: { BoxSource , ConcatSource , RawSource , SourceExt } ;
20- use rspack_util:: { json_stringify, source_map:: SourceMapKind } ;
20+ use rspack_util:: { fx_hash :: FxIndexMap , json_stringify, source_map:: SourceMapKind } ;
2121use rustc_hash:: FxHashMap as HashMap ;
2222use rustc_hash:: FxHashSet as HashSet ;
2323
@@ -146,6 +146,7 @@ pub struct ContextOptions {
146146 pub context : String ,
147147 pub namespace_object : ContextNameSpaceObject ,
148148 pub group_options : Option < GroupOptions > ,
149+ pub replaces : Vec < ( String , u32 , u32 ) > ,
149150 pub start : u32 ,
150151 pub end : u32 ,
151152}
@@ -273,6 +274,13 @@ impl ContextModule {
273274 }
274275 }
275276
277+ fn get_fake_map_init_statement ( & self , fake_map : & FakeMapValue ) -> String {
278+ match fake_map {
279+ FakeMapValue :: Bit ( _) => "" . to_string ( ) ,
280+ FakeMapValue :: Map ( map) => json_stringify ( map) ,
281+ }
282+ }
283+
276284 fn get_return_module_object_source (
277285 & self ,
278286 fake_map : & FakeMapValue ,
@@ -306,36 +314,26 @@ impl ContextModule {
306314 & self ,
307315 dependencies : impl IntoIterator < Item = & DependencyId > ,
308316 compilation : & Compilation ,
309- ) -> HashMap < String , String > {
317+ ) -> FxIndexMap < String , Option < String > > {
318+ let module_graph = compilation. get_module_graph ( ) ;
310319 let dependencies = dependencies. into_iter ( ) ;
311- let mut map = HashMap :: default ( ) ;
312- for dependency in dependencies {
313- if let Some ( module_identifier) = compilation
314- . get_module_graph ( )
315- . module_identifier_by_dependency_id ( dependency)
316- {
317- if let Some ( dependency) = compilation. get_module_graph ( ) . dependency_by_id ( dependency) {
318- let request = if let Some ( d) = dependency. as_module_dependency ( ) {
320+ dependencies
321+ . filter_map ( |dep_id| {
322+ let dep = module_graph. dependency_by_id ( dep_id) . and_then ( |dep| {
323+ if let Some ( d) = dep. as_module_dependency ( ) {
319324 Some ( d. user_request ( ) . to_string ( ) )
320325 } else {
321- dependency
322- . as_context_dependency ( )
323- . map ( |d| d. request ( ) . to_string ( ) )
324- } ;
325- if let Some ( request) = request {
326- map. insert (
327- request,
328- if let Some ( module_id) = compilation. chunk_graph . get_module_id ( * module_identifier) {
329- format ! ( "\" {module_id}\" " )
330- } else {
331- "null" . to_string ( )
332- } ,
333- ) ;
326+ dep. as_context_dependency ( ) . map ( |d| d. request ( ) . to_string ( ) )
334327 }
335- }
336- }
337- }
338- map
328+ } ) ;
329+ let module_id = module_graph
330+ . module_identifier_by_dependency_id ( dep_id)
331+ . and_then ( |module| compilation. chunk_graph . get_module_id ( * module) . clone ( ) ) ;
332+ // module_id could be None in weak mode
333+ dep. map ( |dep| ( dep, module_id) )
334+ } )
335+ . sorted_by ( |( a, _) , ( b, _) | a. cmp ( b) )
336+ . collect ( )
339337 }
340338
341339 fn get_source_for_empty_async_context ( & self , compilation : & Compilation ) -> BoxSource {
@@ -360,6 +358,24 @@ impl ContextModule {
360358 . boxed ( )
361359 }
362360
361+ fn get_source_for_empty_context ( & self , compilation : & Compilation ) -> BoxSource {
362+ RawSource :: from ( formatdoc ! { r#"
363+ function webpackEmptyContext(req) {{
364+ var e = new Error("Cannot find module '" + req + "'");
365+ e.code = 'MODULE_NOT_FOUND';
366+ throw e;
367+ }}
368+ webpackEmptyContext.keys = {keys};
369+ webpackEmptyContext.resolve = webpackEmptyContext;
370+ webpackEmptyContext.id = {id};
371+ module.exports = webpackEmptyContext;
372+ "# ,
373+ keys = returning_function( "[]" , "" ) ,
374+ id = json_stringify( self . id( & compilation. chunk_graph) )
375+ } )
376+ . boxed ( )
377+ }
378+
363379 #[ inline]
364380 fn get_source_string ( & self , compilation : & Compilation ) -> BoxSource {
365381 match self . options . context_options . mode {
@@ -379,6 +395,13 @@ impl ContextModule {
379395 let block = module_graph. block_by_id ( block) . expect ( "should have block" ) ;
380396 self . generate_source ( block. get_dependencies ( ) , compilation)
381397 }
398+ ContextMode :: Sync => {
399+ if !self . get_dependencies ( ) . is_empty ( ) {
400+ self . get_sync_source ( compilation)
401+ } else {
402+ self . get_source_for_empty_context ( compilation)
403+ }
404+ }
382405 _ => self . generate_source ( self . get_dependencies ( ) , compilation) ,
383406 }
384407 }
@@ -530,13 +553,50 @@ impl ContextModule {
530553 webpackAsyncContext.id = {id};
531554 module.exports = webpackAsyncContext;
532555 "# ,
533- map = stringify_map ( & map) ,
556+ map = json_stringify ( & map) ,
534557 keys = returning_function( "Object.keys(map)" , "" ) ,
535558 id = json_stringify( self . id( & compilation. chunk_graph) )
536559 } ) ) ;
537560 source. boxed ( )
538561 }
539562
563+ fn get_sync_source ( & self , compilation : & Compilation ) -> BoxSource {
564+ let dependencies = self . get_dependencies ( ) ;
565+ let map = self . get_user_request_map ( dependencies, compilation) ;
566+ let fake_map = self . get_fake_map ( dependencies, compilation) ;
567+ let return_module_object =
568+ self . get_return_module_object_source ( & fake_map, false , "fakeMap[id]" ) ;
569+ let source = formatdoc ! { r#"
570+ var map = {map};
571+ {fake_map_init_statement}
572+
573+ function webpackContext(req) {{
574+ var id = webpackContextResolve(req);
575+ {return_module_object}
576+ }}
577+ function webpackContextResolve(req) {{
578+ if(!{has_own_property}(map, req)) {{
579+ var e = new Error("Cannot find module '" + req + "'");
580+ e.code = 'MODULE_NOT_FOUND';
581+ throw e;
582+ }}
583+ return map[req];
584+ }}
585+ webpackContext.keys = function webpackContextKeys() {{
586+ return Object.keys(map);
587+ }};
588+ webpackContext.resolve = webpackContextResolve;
589+ module.exports = webpackContext;
590+ webpackContext.id = {id};
591+ "# ,
592+ map = json_stringify( & map) ,
593+ fake_map_init_statement = self . get_fake_map_init_statement( & fake_map) ,
594+ has_own_property = RuntimeGlobals :: HAS_OWN_PROPERTY ,
595+ id = json_stringify( self . id( & compilation. chunk_graph) )
596+ } ;
597+ RawSource :: from ( source) . boxed ( )
598+ }
599+
540600 fn generate_source ( & self , dependencies : & [ DependencyId ] , compilation : & Compilation ) -> BoxSource {
541601 let map = self . get_user_request_map ( dependencies, compilation) ;
542602 let fake_map = self . get_fake_map ( dependencies, compilation) ;
@@ -561,7 +621,7 @@ impl ContextModule {
561621 let mut source = ConcatSource :: default ( ) ;
562622 source. add ( RawSource :: from ( format ! (
563623 "var map = {};\n " ,
564- stringify_map ( & map)
624+ json_stringify ( & map)
565625 ) ) ) ;
566626 if let FakeMapValue :: Map ( map) = & fake_map {
567627 source. add ( RawSource :: from ( format ! (
@@ -623,7 +683,7 @@ impl ContextModule {
623683 source. add ( RawSource :: from ( "\n }\n " ) ) ;
624684
625685 source. add ( RawSource :: from ( format ! (
626- "webpackContext.id = '{}' ;\n " ,
686+ "webpackContext.id = {} ;\n " ,
627687 serde_json:: to_string( self . id( & compilation. chunk_graph) )
628688 . unwrap_or_else( |e| panic!( "{}" , e. to_string( ) ) )
629689 ) ) ) ;
0 commit comments