@@ -2018,7 +2018,7 @@ impl ModuleMap {
20182018 . unwrap ( )
20192019 . clone ( ) ;
20202020 match state. phase {
2021- ModuleImportPhase :: Defer | ModuleImportPhase :: Evaluation => {
2021+ ModuleImportPhase :: Evaluation => {
20222022 let module_id =
20232023 load. root_module_id ( ) . expect ( "Root module should be loaded" ) ;
20242024 let result = self . instantiate_module ( scope, module_id) ;
@@ -2032,6 +2032,95 @@ impl ModuleMap {
20322032 state,
20332033 ) ?;
20342034 }
2035+ ModuleImportPhase :: Defer => {
2036+ // For defer phase imports, the module is instantiated but NOT
2037+ // eagerly evaluated. We call evaluate_for_import_defer which
2038+ // gathers and evaluates async transitive dependencies, then
2039+ // resolve with a deferred namespace that triggers evaluation
2040+ // on first property access.
2041+ let module_id =
2042+ load. root_module_id ( ) . expect ( "Root module should be loaded" ) ;
2043+ let result = self . instantiate_module ( scope, module_id) ;
2044+ if let Err ( exception) = result {
2045+ self . dynamic_import_reject ( scope, dyn_import_id, exception) ;
2046+ continue ;
2047+ }
2048+ let module_handle =
2049+ self . get_handle ( module_id) . expect ( "ModuleInfo not found" ) ;
2050+
2051+ v8:: tc_scope!( let tc_scope, scope) ;
2052+
2053+ let cped = v8:: Local :: new ( tc_scope, state. cped . clone ( ) ) ;
2054+ tc_scope. set_continuation_preserved_embedder_data ( cped) ;
2055+
2056+ let module = v8:: Local :: new ( tc_scope, & module_handle) ;
2057+
2058+ // Gather async transitive dependencies. Returns a promise
2059+ // that resolves when all async deps are ready.
2060+ let maybe_promise = module. evaluate_for_import_defer ( tc_scope) ;
2061+
2062+ let Some ( promise_val) = maybe_promise else {
2063+ let exception = tc_scope. exception ( ) . unwrap ( ) ;
2064+ let exception = v8:: Global :: new ( tc_scope, exception) ;
2065+ self . dynamic_import_reject ( tc_scope, dyn_import_id, exception) ;
2066+ continue ;
2067+ } ;
2068+
2069+ // Get the deferred namespace — this triggers evaluation on
2070+ // first property access.
2071+ let module_namespace = module
2072+ . get_module_namespace_with_phase ( v8:: ModuleImportPhase :: kDefer) ;
2073+
2074+ let promise = v8:: Local :: < v8:: Promise > :: try_from ( promise_val)
2075+ . expect ( "evaluate_for_import_defer should return a promise" ) ;
2076+
2077+ match promise. state ( ) {
2078+ v8:: PromiseState :: Fulfilled => {
2079+ // All async deps are ready, resolve immediately.
2080+ let resolver_handle = self
2081+ . dynamic_import_map
2082+ . borrow_mut ( )
2083+ . remove ( & dyn_import_id)
2084+ . expect ( "Invalid dynamic import id" )
2085+ . resolver ;
2086+ let resolver = resolver_handle. open ( tc_scope) ;
2087+ resolver. resolve ( tc_scope, module_namespace) . unwrap ( ) ;
2088+ tc_scope. perform_microtask_checkpoint ( ) ;
2089+ }
2090+ v8:: PromiseState :: Rejected => {
2091+ let err = promise. result ( tc_scope) ;
2092+ let err = v8:: Global :: new ( tc_scope, err) ;
2093+ self . dynamic_import_reject ( tc_scope, dyn_import_id, err) ;
2094+ }
2095+ v8:: PromiseState :: Pending => {
2096+ // Async deps still loading. Store for later resolution.
2097+ // The module_waker will wake us when the promise settles.
2098+ fn wake_module (
2099+ scope : & mut v8:: PinScope < ' _ , ' _ > ,
2100+ _args : v8:: FunctionCallbackArguments < ' _ > ,
2101+ _rv : v8:: ReturnValue ,
2102+ ) {
2103+ let module_map = JsRealm :: module_map_from ( scope) ;
2104+ module_map. module_waker . wake ( ) ;
2105+ }
2106+
2107+ let wake_module_cb =
2108+ v8:: Function :: builder ( wake_module) . build ( tc_scope) ;
2109+ if let Some ( wake_module_cb) = wake_module_cb {
2110+ promise. then2 ( tc_scope, wake_module_cb, wake_module_cb) ;
2111+ }
2112+
2113+ let dyn_import_mod_evaluate = DynImportModEvaluate {
2114+ load_id : dyn_import_id,
2115+ module_id,
2116+ promise : v8:: Global :: new ( tc_scope, promise) ,
2117+ } ;
2118+ self
2119+ . pending_dyn_mod_evaluations
2120+ . push ( dyn_import_mod_evaluate) ;
2121+ }
2122+ }
2123+ }
20352124 ModuleImportPhase :: Source => {
20362125 let module_reference = load. root_module_reference ( ) . expect (
20372126 "Root module reference had to have been resolved to get here." ,
0 commit comments