@@ -771,17 +771,14 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
771771 }
772772
773773 // compile and eval a JS module
774- // It doesn't wait for callbacks execution
775- pub fn module (self : * JsContext , src : []const u8 , url : []const u8 , cacheable : bool ) ! void {
776- if (! cacheable ) {
777- return self .moduleNoCache (src , url );
778- }
779-
774+ // It returns null if the module is already compiled and in the cache.
775+ // It returns a v8.Promise if the module must be evaluated.
776+ pub fn module (self : * JsContext , src : []const u8 , url : []const u8 , cacheable : bool ) ! ? v8.Promise {
780777 const arena = self .context_arena ;
781778
782- const gop = try self . module_cache . getOrPut ( arena , url );
783- if ( gop . found_existing ) {
784- return ;
779+ if ( cacheable ) {
780+ const value = self . module_cache . get ( url );
781+ if ( value != null ) return null ;
785782 }
786783 errdefer _ = self .module_cache .remove (url );
787784
@@ -791,30 +788,22 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
791788 try self .module_identifier .putNoClobber (arena , m .getIdentityHash (), owned_url );
792789 errdefer _ = self .module_identifier .remove (m .getIdentityHash ());
793790
794- gop .key_ptr .* = owned_url ;
795- gop .value_ptr .* = PersistentModule .init (self .isolate , m );
791+ if (cacheable ) {
792+ try self .module_cache .put (arena , owned_url , PersistentModule .init (self .isolate , m ));
793+ }
796794
797795 // resolveModuleCallback loads module's dependencies.
798796 const v8_context = self .v8_context ;
799797 if (try m .instantiate (v8_context , resolveModuleCallback ) == false ) {
800798 return error .ModuleInstantiationError ;
801799 }
802800
803- _ = try m .evaluate (v8_context );
804- }
805-
806- fn moduleNoCache (self : * JsContext , src : []const u8 , url : []const u8 ) ! void {
807- const m = try compileModule (self .isolate , src , url );
808-
809- const arena = self .context_arena ;
810- const owned_url = try arena .dupe (u8 , url );
811- try self .module_identifier .putNoClobber (arena , m .getIdentityHash (), owned_url );
812-
813- const v8_context = self .v8_context ;
814- if (try m .instantiate (v8_context , resolveModuleCallback ) == false ) {
815- return error .ModuleInstantiationError ;
816- }
817- _ = try m .evaluate (v8_context );
801+ const evaluated = try m .evaluate (v8_context );
802+ // https://v8.github.io/api/head/classv8_1_1Module.html#a1f1758265a4082595757c3251bb40e0f
803+ // Must be a promise that gets returned here.
804+ std .debug .assert (evaluated .isPromise ());
805+ const promise = v8.Promise { .handle = evaluated .handle };
806+ return promise ;
818807 }
819808
820809 // Wrap a v8.Exception
@@ -1573,32 +1562,32 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
15731562 .{ .alloc = .if_needed },
15741563 ) catch unreachable ;
15751564
1576- _dynamicModuleCallback (context , resource_str , normalized_specifier , & resolver );
1565+ log .debug (.js , "dynamic import" , .{
1566+ .specifier = specifier_str ,
1567+ .resource = resource_str ,
1568+ .referrer_full = referrer_full_url ,
1569+ .normalized_specifier = normalized_specifier ,
1570+ });
1571+
1572+ _dynamicModuleCallback (context , normalized_specifier , & resolver ) catch | err | {
1573+ log .err (.js , "dynamic module callback" , .{
1574+ .err = err ,
1575+ });
1576+ // Must be rejected at this point
1577+ // otherwise, we will just wait on a pending promise.
1578+ std .debug .assert (resolver .getPromise ().getState () == .kRejected );
1579+ };
15771580 return @constCast (resolver .getPromise ().handle );
15781581 }
15791582
15801583 fn _dynamicModuleCallback (
15811584 context : * JsContext ,
1582- resource : []const u8 ,
15831585 specifier : []const u8 ,
15841586 resolver : * const v8.PromiseResolver ,
1585- ) void {
1587+ ) ! void {
15861588 const iso = context .isolate ;
15871589 const ctx = context .v8_context ;
15881590
1589- // Check module cache first.
1590- if (context .module_cache .get (specifier )) | cached_module | {
1591- const namespace = cached_module .castToModule ().getModuleNamespace ();
1592- _ = resolver .resolve (ctx , namespace );
1593- return ;
1594- }
1595-
1596- log .info (.js , "dynamic import" , .{
1597- .specifier = specifier ,
1598- .resource = resource ,
1599- .normalized = specifier ,
1600- });
1601-
16021591 const module_loader = context .module_loader ;
16031592 const source = module_loader .func (module_loader .ptr , specifier ) catch {
16041593 const error_msg = v8 .String .initUtf8 (iso , "Failed to load module" );
@@ -1614,71 +1603,30 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
16141603 try_catch .init (context );
16151604 defer try_catch .deinit ();
16161605
1617- const new_module = compileModule ( iso , source , specifier ) catch {
1606+ const maybe_promise = context . module ( source , specifier , true ) catch {
16181607 log .err (.js , "module compilation failed" , .{
16191608 .specifier = specifier ,
16201609 .exception = try_catch .exception (context .call_arena ) catch "unknown error" ,
16211610 .stack = try_catch .stack (context .call_arena ) catch null ,
1622- });
1623- const error_msg = if (try_catch .hasCaught ()) blk : {
1624- const exception_str = try_catch .exception (context .call_arena ) catch "Compilation error" ;
1625- break :blk v8 .String .initUtf8 (iso , exception_str orelse "Compilation error" );
1626- } else v8 .String .initUtf8 (iso , "Module compilation failed" );
1627-
1628- _ = resolver .reject (ctx , error_msg .toValue ());
1629- return ;
1630- };
1631-
1632- // Insert into Module Cache.
1633- context .module_identifier .putNoClobber (context .context_arena , new_module .getIdentityHash (), specifier ) catch unreachable ;
1634- context .module_cache .putNoClobber (context .context_arena , specifier , v8 .Persistent (v8 .Module ).init (iso , new_module )) catch unreachable ;
1635-
1636- const instantiated = new_module .instantiate (ctx , JsContext .resolveModuleCallback ) catch {
1637- log .err (.js , "module instantiation failed" , .{
1638- .specifier = specifier ,
1639- .exception = try_catch .exception (context .call_arena ) catch "unknown error" ,
1640- .stack = try_catch .stack (context .call_arena ) catch null ,
1641- });
1642- const error_msg = if (try_catch .hasCaught ()) blk : {
1643- const exception_str = try_catch .exception (context .call_arena ) catch "Instantiation error" ;
1644- break :blk v8 .String .initUtf8 (iso , exception_str orelse "Instantiation error" );
1645- } else v8 .String .initUtf8 (iso , "Module instantiation failed" );
1646-
1647- _ = resolver .reject (ctx , error_msg .toValue ());
1648- return ;
1649- };
1650-
1651- if (! instantiated ) {
1652- const error_msg = v8 .String .initUtf8 (iso , "Module did not instantiate" );
1653- _ = resolver .reject (ctx , error_msg .toValue ());
1654- return ;
1655- }
1656-
1657- const evaluated = new_module .evaluate (ctx ) catch {
1658- log .err (.js , "module evaluation failed" , .{
1659- .specifier = specifier ,
1660- .exception = try_catch .exception (context .call_arena ) catch "unknown error" ,
1661- .stack = try_catch .stack (context .call_arena ) catch null ,
16621611 .line = try_catch .sourceLineNumber () orelse 0 ,
16631612 });
16641613 const error_msg = if (try_catch .hasCaught ()) blk : {
16651614 const exception_str = try_catch .exception (context .call_arena ) catch "Evaluation error" ;
16661615 break :blk v8 .String .initUtf8 (iso , exception_str orelse "Evaluation error" );
16671616 } else v8 .String .initUtf8 (iso , "Module evaluation failed" );
1668-
16691617 _ = resolver .reject (ctx , error_msg .toValue ());
16701618 return ;
16711619 };
1620+ const new_module = context .module_cache .get (specifier ).? .castToModule ();
16721621
1673- if (evaluated .isPromise ()) {
1674- const promise = v8.Promise { .handle = evaluated .handle };
1675-
1622+ if (maybe_promise ) | promise | {
1623+ // This means we must wait for the evaluation.
16761624 const EvaluationData = struct {
16771625 module : v8 .Persistent (v8 .Module ),
16781626 resolver : v8 .Persistent (v8 .PromiseResolver ),
16791627 };
16801628
1681- const ev_data = context .context_arena .create (EvaluationData ) catch unreachable ;
1629+ const ev_data = try context .context_arena .create (EvaluationData );
16821630 ev_data .* = .{
16831631 .module = v8 .Persistent (v8 .Module ).init (iso , new_module ),
16841632 .resolver = v8 .Persistent (v8 .PromiseResolver ).init (iso , resolver .* ),
@@ -1695,7 +1643,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
16951643 const cb_resolver = data .resolver .castToPromiseResolver ();
16961644
16971645 const namespace = cb_module .getModuleNamespace ();
1698- log .warn (.js , "module then promise" , .{
1646+ log .info (.js , "dynamic import complete" , .{
1647+ .module = cb_module ,
16991648 .namespace = namespace ,
17001649 });
17011650 _ = cb_resolver .resolve (cb_context , namespace );
@@ -1704,11 +1653,15 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
17041653
17051654 const catch_callback = v8 .Function .initWithData (ctx , struct {
17061655 pub fn callback (info : ? * const v8.c.FunctionCallbackInfo ) callconv (.c ) void {
1707- log .warn (.js , "module catch promise" , .{});
17081656 const cb_info = v8.FunctionCallbackInfo { .handle = info .? };
17091657 const cb_context = cb_info .getIsolate ().getCurrentContext ();
17101658 const data : * EvaluationData = @ptrCast (@alignCast (cb_info .getExternalValue ()));
1659+ const cb_module = data .module .castToModule ();
17111660 const cb_resolver = data .resolver .castToPromiseResolver ();
1661+
1662+ log .err (.js , "dynamic import failed" , .{
1663+ .module = cb_module ,
1664+ });
17121665 _ = cb_resolver .reject (cb_context , cb_info .getData ());
17131666 }
17141667 }.callback , external );
@@ -1723,8 +1676,14 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
17231676 return ;
17241677 };
17251678 } else {
1679+ // This means it is already present in the cache.
17261680 const namespace = new_module .getModuleNamespace ();
1681+ log .info (.js , "dynamic import complete" , .{
1682+ .module = new_module ,
1683+ .namespace = namespace ,
1684+ });
17271685 _ = resolver .resolve (ctx , namespace );
1686+ return ;
17281687 }
17291688 }
17301689 };
0 commit comments