@@ -194,7 +194,11 @@ pub const Session = struct {
194194 // Use the page_arena for this, which has a more appropriate lifetime
195195 // and which has more retained memory between sessions and pages.
196196 const arena = self .browser .page_arena .allocator ();
197- const body = try self .page .? .fetchData (arena , specifier );
197+ const body = try self .page .? .fetchData (
198+ arena ,
199+ specifier ,
200+ if (self .page .? .current_script ) | s | s .src else null ,
201+ );
198202 return self .env .compileModule (body , specifier );
199203 }
200204
@@ -283,6 +287,10 @@ pub const Page = struct {
283287
284288 raw_data : ? []const u8 = null ,
285289
290+ // current_script is the script currently evaluated by the page.
291+ // current_script could by fetch module to resolve module's url to fetch.
292+ current_script : ? * const Script = null ,
293+
286294 fn init (session : * Session ) Page {
287295 return .{
288296 .session = session ,
@@ -546,6 +554,9 @@ pub const Page = struct {
546554 // if no src is present, we evaluate the text source.
547555 // https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
548556 fn evalScript (self : * Page , s : Script ) ! void {
557+ self .current_script = & s ;
558+ defer self .current_script = null ;
559+
549560 // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-classic-script
550561 const opt_src = try parser .elementGetAttribute (s .element , "src" );
551562 if (opt_src ) | src | {
@@ -590,13 +601,27 @@ pub const Page = struct {
590601 JsErr ,
591602 };
592603
604+ // fetchData returns the data corresponding to the src target.
605+ // It resolves src using the page's uri.
606+ // If a base path is given, src is resolved according to the base first.
593607 // the caller owns the returned string
594- fn fetchData (self : * Page , arena : Allocator , src : []const u8 ) ! []const u8 {
608+ fn fetchData (self : * Page , arena : Allocator , src : []const u8 , base : ? [] const u8 ) ! []const u8 {
595609 log .debug ("starting fetch {s}" , .{src });
596610
597611 var buffer : [1024 ]u8 = undefined ;
598612 var b : []u8 = buffer [0.. ];
599- const u = try std .Uri .resolve_inplace (self .uri , src , & b );
613+
614+ var res_src = src ;
615+
616+ // if a base path is given, we resolve src using base.
617+ if (base ) | _base | {
618+ const dir = std .fs .path .dirname (_base );
619+ if (dir ) | _dir | {
620+ res_src = try std .fs .path .resolve (arena , &.{ _dir , src });
621+ }
622+ }
623+
624+ const u = try std .Uri .resolve_inplace (self .uri , res_src , & b );
600625
601626 var fetchres = try self .session .loader .get (arena , u );
602627 defer fetchres .deinit ();
@@ -624,7 +649,7 @@ pub const Page = struct {
624649 // received.
625650 fn fetchScript (self : * Page , s : Script ) ! void {
626651 const arena = self .arena ;
627- const body = try self .fetchData (arena , s .src );
652+ const body = try self .fetchData (arena , s .src , null );
628653 // TODO: change to &self.session.env when
629654 // https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
630655 try s .eval (arena , self .session .env , body );
0 commit comments