@@ -184,17 +184,18 @@ pub const Session = struct {
184184 _ = referrer ;
185185
186186 const self : * Session = @ptrCast (@alignCast (ctx ));
187-
188- if (self .page == null ) {
189- return error .NoPage ;
190- }
187+ const page = &(self .page orelse return error .NoPage );
191188
192189 log .debug ("fetch module: specifier: {s}" , .{specifier });
193190 // fetchModule is called within the context of processing a page.
194191 // Use the page_arena for this, which has a more appropriate lifetime
195192 // and which has more retained memory between sessions and pages.
196193 const arena = self .browser .page_arena .allocator ();
197- const body = try self .page .? .fetchData (arena , specifier );
194+ const body = try page .fetchData (
195+ arena ,
196+ specifier ,
197+ if (page .current_script ) | s | s .src else null ,
198+ );
198199 return self .env .compileModule (body , specifier );
199200 }
200201
@@ -283,6 +284,10 @@ pub const Page = struct {
283284
284285 raw_data : ? []const u8 = null ,
285286
287+ // current_script is the script currently evaluated by the page.
288+ // current_script could by fetch module to resolve module's url to fetch.
289+ current_script : ? * const Script = null ,
290+
286291 fn init (session : * Session ) Page {
287292 return .{
288293 .session = session ,
@@ -504,7 +509,7 @@ pub const Page = struct {
504509 // > page.
505510 // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#notes
506511 try parser .documentHTMLSetCurrentScript (html_doc , @ptrCast (e ));
507- self .evalScript (script ) catch | err | log .warn ("evaljs: {any}" , .{err });
512+ self .evalScript (& script ) catch | err | log .warn ("evaljs: {any}" , .{err });
508513 try parser .documentHTMLSetCurrentScript (html_doc , null );
509514 }
510515
@@ -523,7 +528,7 @@ pub const Page = struct {
523528 // eval async scripts.
524529 for (sasync .items ) | s | {
525530 try parser .documentHTMLSetCurrentScript (html_doc , @ptrCast (s .element ));
526- self .evalScript (s ) catch | err | log .warn ("evaljs: {any}" , .{err });
531+ self .evalScript (& s ) catch | err | log .warn ("evaljs: {any}" , .{err });
527532 try parser .documentHTMLSetCurrentScript (html_doc , null );
528533 }
529534
@@ -545,7 +550,10 @@ pub const Page = struct {
545550 // evalScript evaluates the src in priority.
546551 // if no src is present, we evaluate the text source.
547552 // https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
548- fn evalScript (self : * Page , s : Script ) ! void {
553+ fn evalScript (self : * Page , s : * const Script ) ! void {
554+ self .current_script = s ;
555+ defer self .current_script = null ;
556+
549557 // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-classic-script
550558 const opt_src = try parser .elementGetAttribute (s .element , "src" );
551559 if (opt_src ) | src | {
@@ -590,13 +598,27 @@ pub const Page = struct {
590598 JsErr ,
591599 };
592600
601+ // fetchData returns the data corresponding to the src target.
602+ // It resolves src using the page's uri.
603+ // If a base path is given, src is resolved according to the base first.
593604 // the caller owns the returned string
594- fn fetchData (self : * Page , arena : Allocator , src : []const u8 ) ! []const u8 {
605+ fn fetchData (self : * const Page , arena : Allocator , src : [] const u8 , base : ? []const u8 ) ! []const u8 {
595606 log .debug ("starting fetch {s}" , .{src });
596607
597608 var buffer : [1024 ]u8 = undefined ;
598609 var b : []u8 = buffer [0.. ];
599- const u = try std .Uri .resolve_inplace (self .uri , src , & b );
610+
611+ var res_src = src ;
612+
613+ // if a base path is given, we resolve src using base.
614+ if (base ) | _base | {
615+ const dir = std .fs .path .dirname (_base );
616+ if (dir ) | _dir | {
617+ res_src = try std .fs .path .resolve (arena , &.{ _dir , src });
618+ }
619+ }
620+
621+ const u = try std .Uri .resolve_inplace (self .uri , res_src , & b );
600622
601623 var fetchres = try self .session .loader .get (arena , u );
602624 defer fetchres .deinit ();
@@ -622,9 +644,10 @@ pub const Page = struct {
622644
623645 // fetchScript senf a GET request to the src and execute the script
624646 // received.
625- fn fetchScript (self : * Page , s : Script ) ! void {
647+ fn fetchScript (self : * const Page , s : * const Script ) ! void {
626648 const arena = self .arena ;
627- const body = try self .fetchData (arena , s .src );
649+
650+ const body = try self .fetchData (arena , s .src , null );
628651 // TODO: change to &self.session.env when
629652 // https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
630653 try s .eval (arena , self .session .env , body );
0 commit comments