@@ -695,17 +695,14 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
695695 }
696696
697697 // compile and eval a JS module
698- // It doesn't wait for callbacks execution
699- pub fn module (self : * JsContext , src : []const u8 , url : []const u8 , cacheable : bool ) ! void {
700- if (! cacheable ) {
701- return self .moduleNoCache (src , url );
702- }
703-
698+ // It returns null if the module is already compiled and in the cache.
699+ // It returns a v8.Promise if the module must be evaluated.
700+ pub fn module (self : * JsContext , src : []const u8 , url : []const u8 , cacheable : bool ) ! ? v8.Promise {
704701 const arena = self .context_arena ;
705702
706- const gop = try self . module_cache . getOrPut ( arena , url );
707- if ( gop . found_existing ) {
708- return ;
703+ if ( cacheable ) {
704+ const value = self . module_cache . get ( url );
705+ if ( value != null ) return null ;
709706 }
710707 errdefer _ = self .module_cache .remove (url );
711708
@@ -715,28 +712,22 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
715712 try self .module_identifier .putNoClobber (arena , m .getIdentityHash (), owned_url );
716713 errdefer _ = self .module_identifier .remove (m .getIdentityHash ());
717714
718- gop .key_ptr .* = owned_url ;
719- gop .value_ptr .* = PersistentModule .init (self .isolate , m );
715+ if (cacheable ) {
716+ try self .module_cache .put (arena , owned_url , PersistentModule .init (self .isolate , m ));
717+ }
720718
721719 // resolveModuleCallback loads module's dependencies.
722720 const v8_context = self .v8_context ;
723721 if (try m .instantiate (v8_context , resolveModuleCallback ) == false ) {
724722 return error .ModuleInstantiationError ;
725723 }
726724
727- _ = try m .evaluate (v8_context );
728- }
729-
730- fn moduleNoCache (self : * JsContext , src : []const u8 , url : []const u8 ) ! void {
731- const m = try compileModule (self .isolate , src , url );
732- const v8_context = self .v8_context ;
733- if (try m .instantiate (v8_context , resolveModuleCallback ) == false ) {
734- return error .ModuleInstantiationError ;
735- }
736- const arena = self .context_arena ;
737- const owned_url = try arena .dupe (u8 , url );
738- try self .module_identifier .putNoClobber (arena , m .getIdentityHash (), owned_url );
739- _ = try m .evaluate (v8_context );
725+ const evaluated = try m .evaluate (v8_context );
726+ // https://v8.github.io/api/head/classv8_1_1Module.html#a1f1758265a4082595757c3251bb40e0f
727+ // Must be a promise that gets returned here.
728+ std .debug .assert (evaluated .isPromise ());
729+ const promise = v8.Promise { .handle = evaluated .handle };
730+ return promise ;
740731 }
741732
742733 // Wrap a v8.Exception
@@ -1412,27 +1403,28 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
14121403 .{ .alloc = .if_needed },
14131404 ) catch unreachable ;
14141405
1415- _dynamicModuleCallback (context , resource_str , normalized_specifier , & resolver );
1406+ log .debug (.js , "dynamic import" , .{
1407+ .specifier = specifier_str ,
1408+ .resource = resource_str ,
1409+ .referrer_full = referrer_full_url ,
1410+ .normalized_specifier = normalized_specifier ,
1411+ });
1412+
1413+ _dynamicModuleCallback (context , normalized_specifier , & resolver ) catch | err | {
1414+ log .err (.js , "dynamic module callback" , .{
1415+ .err = err ,
1416+ });
1417+ // Must be rejected at this point
1418+ // otherwise, we will just wait on a pending promise.
1419+ std .debug .assert (resolver .getPromise ().getState () == .kRejected );
1420+ };
14161421 return @constCast (resolver .getPromise ().handle );
14171422 }
14181423
1419- fn _dynamicModuleCallback (context : * JsContext , resource : [] const u8 , specifier : []const u8 , resolver : * const v8.PromiseResolver ) void {
1424+ fn _dynamicModuleCallback (context : * JsContext , specifier : []const u8 , resolver : * const v8.PromiseResolver ) ! void {
14201425 const iso = context .isolate ;
14211426 const ctx = context .v8_context ;
14221427
1423- // Check module cache first.
1424- if (context .module_cache .get (specifier )) | cached_module | {
1425- const namespace = cached_module .castToModule ().getModuleNamespace ();
1426- _ = resolver .resolve (ctx , namespace );
1427- return ;
1428- }
1429-
1430- log .info (.js , "dynamic import" , .{
1431- .specifier = specifier ,
1432- .resource = resource ,
1433- .normalized = specifier ,
1434- });
1435-
14361428 const module_loader = context .module_loader ;
14371429 const source = module_loader .func (module_loader .ptr , specifier ) catch {
14381430 const error_msg = v8 .String .initUtf8 (iso , "Failed to load module" );
@@ -1448,71 +1440,30 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
14481440 try_catch .init (context );
14491441 defer try_catch .deinit ();
14501442
1451- const new_module = compileModule ( iso , source , specifier ) catch {
1443+ const maybe_promise = context . module ( source , specifier , true ) catch {
14521444 log .err (.js , "module compilation failed" , .{
14531445 .specifier = specifier ,
14541446 .exception = try_catch .exception (context .call_arena ) catch "unknown error" ,
14551447 .stack = try_catch .stack (context .call_arena ) catch null ,
1456- });
1457- const error_msg = if (try_catch .hasCaught ()) blk : {
1458- const exception_str = try_catch .exception (context .call_arena ) catch "Compilation error" ;
1459- break :blk v8 .String .initUtf8 (iso , exception_str orelse "Compilation error" );
1460- } else v8 .String .initUtf8 (iso , "Module compilation failed" );
1461-
1462- _ = resolver .reject (ctx , error_msg .toValue ());
1463- return ;
1464- };
1465-
1466- // Insert into Module Cache.
1467- context .module_identifier .putNoClobber (context .context_arena , new_module .getIdentityHash (), specifier ) catch unreachable ;
1468- context .module_cache .putNoClobber (context .context_arena , specifier , v8 .Persistent (v8 .Module ).init (iso , new_module )) catch unreachable ;
1469-
1470- const instantiated = new_module .instantiate (ctx , JsContext .resolveModuleCallback ) catch {
1471- log .err (.js , "module instantiation failed" , .{
1472- .specifier = specifier ,
1473- .exception = try_catch .exception (context .call_arena ) catch "unknown error" ,
1474- .stack = try_catch .stack (context .call_arena ) catch null ,
1475- });
1476- const error_msg = if (try_catch .hasCaught ()) blk : {
1477- const exception_str = try_catch .exception (context .call_arena ) catch "Instantiation error" ;
1478- break :blk v8 .String .initUtf8 (iso , exception_str orelse "Instantiation error" );
1479- } else v8 .String .initUtf8 (iso , "Module instantiation failed" );
1480-
1481- _ = resolver .reject (ctx , error_msg .toValue ());
1482- return ;
1483- };
1484-
1485- if (! instantiated ) {
1486- const error_msg = v8 .String .initUtf8 (iso , "Module did not instantiate" );
1487- _ = resolver .reject (ctx , error_msg .toValue ());
1488- return ;
1489- }
1490-
1491- const evaluated = new_module .evaluate (ctx ) catch {
1492- log .err (.js , "module evaluation failed" , .{
1493- .specifier = specifier ,
1494- .exception = try_catch .exception (context .call_arena ) catch "unknown error" ,
1495- .stack = try_catch .stack (context .call_arena ) catch null ,
14961448 .line = try_catch .sourceLineNumber () orelse 0 ,
14971449 });
14981450 const error_msg = if (try_catch .hasCaught ()) blk : {
14991451 const exception_str = try_catch .exception (context .call_arena ) catch "Evaluation error" ;
15001452 break :blk v8 .String .initUtf8 (iso , exception_str orelse "Evaluation error" );
15011453 } else v8 .String .initUtf8 (iso , "Module evaluation failed" );
1502-
15031454 _ = resolver .reject (ctx , error_msg .toValue ());
15041455 return ;
15051456 };
1457+ const new_module = context .module_cache .get (specifier ).? .castToModule ();
15061458
1507- if (evaluated .isPromise ()) {
1508- const promise = v8.Promise { .handle = evaluated .handle };
1509-
1459+ if (maybe_promise ) | promise | {
1460+ // This means we must wait for the evaluation.
15101461 const EvaluationData = struct {
15111462 module : v8 .Persistent (v8 .Module ),
15121463 resolver : v8 .Persistent (v8 .PromiseResolver ),
15131464 };
15141465
1515- const ev_data = context .context_arena .create (EvaluationData ) catch unreachable ;
1466+ const ev_data = try context .context_arena .create (EvaluationData );
15161467 ev_data .* = .{
15171468 .module = v8 .Persistent (v8 .Module ).init (iso , new_module ),
15181469 .resolver = v8 .Persistent (v8 .PromiseResolver ).init (iso , resolver .* ),
@@ -1529,7 +1480,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
15291480 const cb_resolver = data .resolver .castToPromiseResolver ();
15301481
15311482 const namespace = cb_module .getModuleNamespace ();
1532- log .warn (.js , "module then promise" , .{
1483+ log .info (.js , "dynamic import complete" , .{
1484+ .module = cb_module ,
15331485 .namespace = namespace ,
15341486 });
15351487 _ = cb_resolver .resolve (cb_context , namespace );
@@ -1538,11 +1490,15 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
15381490
15391491 const catch_callback = v8 .Function .initWithData (ctx , struct {
15401492 pub fn callback (info : ? * const v8.c.FunctionCallbackInfo ) callconv (.c ) void {
1541- log .warn (.js , "module catch promise" , .{});
15421493 const cb_info = v8.FunctionCallbackInfo { .handle = info .? };
15431494 const cb_context = cb_info .getIsolate ().getCurrentContext ();
15441495 const data : * EvaluationData = @ptrCast (@alignCast (cb_info .getExternalValue ()));
1496+ const cb_module = data .module .castToModule ();
15451497 const cb_resolver = data .resolver .castToPromiseResolver ();
1498+
1499+ log .err (.js , "dynamic import failed" , .{
1500+ .module = cb_module ,
1501+ });
15461502 _ = cb_resolver .reject (cb_context , cb_info .getData ());
15471503 }
15481504 }.callback , external );
@@ -1557,8 +1513,14 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
15571513 return ;
15581514 };
15591515 } else {
1516+ // This means it is already present in the cache.
15601517 const namespace = new_module .getModuleNamespace ();
1518+ log .info (.js , "dynamic import complete" , .{
1519+ .module = new_module ,
1520+ .namespace = namespace ,
1521+ });
15611522 _ = resolver .resolve (ctx , namespace );
1523+ return ;
15621524 }
15631525 }
15641526 };
0 commit comments