@@ -930,9 +930,7 @@ pub fn execute_module(
930930 prefetch_module_imports ( tc, bridge_ctx, module, resource_name_str) ;
931931
932932 // Instantiate (calls resolve callback for each import — mostly cache hits now)
933- eprintln ! ( "[v8-runtime] instantiating module..." ) ;
934933 let inst_result = module. instantiate_module ( tc, module_resolve_callback) ;
935- eprintln ! ( "[v8-runtime] instantiate result: {:?}" , inst_result. is_some( ) ) ;
936934 if inst_result. is_none ( )
937935 {
938936 clear_module_state ( ) ;
@@ -946,10 +944,7 @@ pub fn execute_module(
946944 }
947945
948946 // Evaluate
949- let eval_start = std:: time:: Instant :: now ( ) ;
950- eprintln ! ( "[v8-runtime] evaluating module (resource={})..." , resource_name_str) ;
951947 let eval_result = module. evaluate ( tc) ;
952- eprintln ! ( "[v8-runtime] evaluate done: result={} elapsed={}ms" , eval_result. is_some( ) , eval_start. elapsed( ) . as_millis( ) ) ;
953948 if eval_result. is_none ( ) {
954949 clear_module_state ( ) ;
955950 return match tc. exception ( ) {
@@ -1028,7 +1023,8 @@ pub fn execute_module(
10281023 }
10291024 } ;
10301025
1031- clear_module_state ( ) ;
1026+ // Keep module resolve state available after the initial module finishes.
1027+ // Dynamic imports can still fire later on the same session event loop.
10321028 ( 0 , Some ( exports_bytes) , None )
10331029 }
10341030}
@@ -1122,11 +1118,7 @@ fn prefetch_module_imports(
11221118
11231119 // Detect CJS and wrap in ESM shim if needed
11241120 let is_cjs = is_likely_cjs ( source_code) ;
1125- if resolved_path. contains ( "balanced" ) {
1126- eprintln ! ( "[v8-runtime] balanced-match check: is_cjs={} source_len={} first_100={}" , is_cjs, source_code. len( ) , & source_code[ ..std:: cmp:: min( source_code. len( ) , 100 ) ] ) ;
1127- }
11281121 let effective_source = if is_cjs {
1129- eprintln ! ( "[v8-runtime] CJS→ESM shim (prefetch): {}" , resolved_path) ;
11301122 let exports = extract_cjs_export_names ( source_code) ;
11311123 let mut shim = format ! (
11321124 "const _cjsModule = globalThis._requireFrom(\" {}\" , \" /\" );\n export default _cjsModule;\n " ,
@@ -1219,9 +1211,9 @@ fn resolve_or_compile_module<'s>(
12191211 // Phase 2: Get bridge context.
12201212 let bridge_ctx_ptr = MODULE_RESOLVE_STATE . with ( |cell| {
12211213 let borrow = cell. borrow ( ) ;
1222- let state = borrow. as_ref ( ) . expect ( "module resolve state not set" ) ;
1223- state. bridge_ctx
1214+ borrow. as_ref ( ) . map ( |state| state. bridge_ctx )
12241215 } ) ;
1216+ let bridge_ctx_ptr = bridge_ctx_ptr?;
12251217 let ctx = unsafe { & * bridge_ctx_ptr } ;
12261218
12271219 // Phase 3: Resolve module path.
@@ -1238,16 +1230,13 @@ fn resolve_or_compile_module<'s>(
12381230 }
12391231
12401232 // Phase 5: Load and compile the module source.
1241- eprintln ! ( "[v8-runtime] loading module: {} (specifier={} referrer={})" , & resolved_path, specifier_str, referrer_name) ;
12421233 let raw_source = load_module_via_ipc ( scope, ctx, & resolved_path) ?;
1243- eprintln ! ( "[v8-runtime] loaded {} bytes, is_cjs={}" , raw_source. len( ) , is_likely_cjs( & raw_source) ) ;
12441234
12451235 // Phase 5b: Detect CJS modules and wrap in ESM shim.
12461236 // CJS modules use module.exports/exports which isn't valid ESM syntax.
12471237 // Real Node.js wraps CJS in a default+named export shim. We do the same
12481238 // by generating: `const _m = globalThis._requireFrom(path, "/"); export default _m; export const {named1, named2, ...} = _m;`
12491239 let source_code = if is_likely_cjs ( & raw_source) {
1250- eprintln ! ( "[v8-runtime] CJS→ESM shim for: {}" , & resolved_path) ;
12511240 // Extract potential named exports by scanning for common patterns
12521241 let exports = extract_cjs_export_names ( & raw_source) ;
12531242 let mut shim = format ! (
@@ -1291,8 +1280,6 @@ fn resolve_or_compile_module<'s>(
12911280 } ;
12921281 let mut compiled = v8:: script_compiler:: Source :: new ( v8_source, Some ( & origin) ) ;
12931282 let module = v8:: script_compiler:: compile_module ( scope, & mut compiled) ?;
1294- eprintln ! ( "[v8-runtime] compiled OK: {}" , & resolved_path) ;
1295-
12961283 MODULE_RESOLVE_STATE . with ( |cell| {
12971284 if let Some ( state) = cell. borrow_mut ( ) . as_mut ( ) {
12981285 state
@@ -1548,13 +1535,10 @@ fn module_resolve_callback<'a>(
15481535
15491536 let referrer_name = MODULE_RESOLVE_STATE . with ( |cell| {
15501537 let borrow = cell. borrow ( ) ;
1551- let state = borrow. as_ref ( ) . expect ( "module resolve state not set" ) ;
1552- state
1553- . module_names
1554- . get ( & referrer_hash)
1555- . cloned ( )
1556- . unwrap_or_default ( )
1538+ let state = borrow. as_ref ( ) ?;
1539+ state. module_names . get ( & referrer_hash) . cloned ( )
15571540 } ) ;
1541+ let referrer_name = referrer_name?;
15581542 resolve_or_compile_module ( scope, & specifier_str, & referrer_name)
15591543}
15601544
@@ -1627,7 +1611,6 @@ fn load_module_via_ipc(
16271611 } ;
16281612
16291613 let ipc_result = ctx. sync_call ( "_loadFile" , args) ;
1630- eprintln ! ( "[v8-runtime] _loadFile result: is_ok={} has_bytes={}" , ipc_result. is_ok( ) , ipc_result. as_ref( ) . ok( ) . map( |r| r. is_some( ) ) . unwrap_or( false ) ) ;
16311614 match ipc_result {
16321615 Ok ( Some ( bytes) ) => match deserialize_v8_value ( scope, & bytes) {
16331616 Ok ( val) => {
@@ -5021,6 +5004,87 @@ mod tests {
50215004 ) ;
50225005 }
50235006
5007+ // Part 69: Dynamic import works after execute_module returns
5008+ {
5009+ let mut iso = isolate:: create_isolate ( None ) ;
5010+ iso. set_host_import_module_dynamically_callback ( dynamic_import_callback) ;
5011+ iso. set_host_initialize_import_meta_object_callback ( import_meta_object_callback) ;
5012+ let ctx = isolate:: create_context ( & mut iso) ;
5013+
5014+ let mut response_buf = Vec :: new ( ) ;
5015+
5016+ let resolve_result = v8_serialize_str ( & mut iso, & ctx, "/dep.mjs" ) ;
5017+ crate :: ipc_binary:: write_frame (
5018+ & mut response_buf,
5019+ & crate :: ipc_binary:: BinaryFrame :: BridgeResponse {
5020+ session_id : String :: new ( ) ,
5021+ call_id : 1 ,
5022+ status : 0 ,
5023+ payload : resolve_result,
5024+ } ,
5025+ )
5026+ . unwrap ( ) ;
5027+
5028+ let load_result = v8_serialize_str ( & mut iso, & ctx, "export const value = 42;" ) ;
5029+ crate :: ipc_binary:: write_frame (
5030+ & mut response_buf,
5031+ & crate :: ipc_binary:: BinaryFrame :: BridgeResponse {
5032+ session_id : String :: new ( ) ,
5033+ call_id : 2 ,
5034+ status : 0 ,
5035+ payload : load_result,
5036+ } ,
5037+ )
5038+ . unwrap ( ) ;
5039+
5040+ let bridge_ctx = BridgeCallContext :: new (
5041+ Box :: new ( Vec :: new ( ) ) ,
5042+ Box :: new ( Cursor :: new ( response_buf) ) ,
5043+ "test-session" . into ( ) ,
5044+ ) ;
5045+
5046+ let user_code = r#"
5047+ globalThis.loadDep = async () => (await import("./dep.mjs")).value;
5048+ export const ready = true;
5049+ "# ;
5050+ let ( code, exports, error) = {
5051+ let scope = & mut v8:: HandleScope :: new ( & mut iso) ;
5052+ let local = v8:: Local :: new ( scope, & ctx) ;
5053+ let scope = & mut v8:: ContextScope :: new ( scope, local) ;
5054+ execute_module (
5055+ scope,
5056+ & bridge_ctx,
5057+ "" ,
5058+ user_code,
5059+ Some ( "/app/main.mjs" ) ,
5060+ & mut None ,
5061+ )
5062+ } ;
5063+
5064+ assert_eq ! ( code, 0 , "error: {:?}" , error) ;
5065+ assert ! ( error. is_none( ) ) ;
5066+ assert ! ( exports. is_some( ) ) ;
5067+
5068+ {
5069+ let scope = & mut v8:: HandleScope :: new ( & mut iso) ;
5070+ let local = v8:: Local :: new ( scope, & ctx) ;
5071+ let scope = & mut v8:: ContextScope :: new ( scope, local) ;
5072+ let tc = & mut v8:: TryCatch :: new ( scope) ;
5073+ let source = v8:: String :: new (
5074+ tc,
5075+ "globalThis.__depPromise = globalThis.loadDep().then((value) => { globalThis.__depValue = value; return value; });" ,
5076+ )
5077+ . unwrap ( ) ;
5078+ let script = v8:: Script :: compile ( tc, source, None ) . unwrap ( ) ;
5079+ assert ! ( script. run( tc) . is_some( ) ) ;
5080+ tc. perform_microtask_checkpoint ( ) ;
5081+ assert ! ( tc. exception( ) . is_none( ) ) ;
5082+ }
5083+
5084+ assert_eq ! ( eval( & mut iso, & ctx, "String(globalThis.__depValue)" ) , "42" ) ;
5085+ clear_module_state ( ) ;
5086+ }
5087+
50245088 // --- Part 57: serialize_v8_value_into reuses buffer capacity ---
50255089 {
50265090 let mut iso = isolate:: create_isolate ( None ) ;
0 commit comments