Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions src/browser/browser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,11 @@ pub const Session = struct {
// Use the page_arena for this, which has a more appropriate lifetime
// and which has more retained memory between sessions and pages.
const arena = self.browser.page_arena.allocator();
const body = try self.page.?.fetchData(arena, specifier);
const body = try self.page.?.fetchData(
arena,
specifier,
if (self.page.?.current_script) |s| s.src else null,
);
return self.env.compileModule(body, specifier);
}

Expand Down Expand Up @@ -283,6 +287,10 @@ pub const Page = struct {

raw_data: ?[]const u8 = null,

// current_script is the script currently evaluated by the page.
// current_script could by fetch module to resolve module's url to fetch.
current_script: ?*const Script = null,

fn init(session: *Session) Page {
return .{
.session = session,
Expand Down Expand Up @@ -546,6 +554,9 @@ pub const Page = struct {
// if no src is present, we evaluate the text source.
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
fn evalScript(self: *Page, s: Script) !void {
self.current_script = &s;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something weird about taking the address of this value and storing it as a field. But it does work, especially since you null it before you exit.

Would be nice if the module loader took arbitrary state per-load, but that's a bigger change, and would likely require allocating something on the heap to pass it through.

I do think evalScript should take a *const Script though. It won't change much - you'll still be storing a stack address in the field - but there's no reason for it to take a copy.

defer self.current_script = null;

// https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-classic-script
const opt_src = try parser.elementGetAttribute(s.element, "src");
if (opt_src) |src| {
Expand Down Expand Up @@ -590,13 +601,27 @@ pub const Page = struct {
JsErr,
};

// fetchData returns the data corresponding to the src target.
// It resolves src using the page's uri.
// If a base path is given, src is resolved according to the base first.
// the caller owns the returned string
fn fetchData(self: *Page, arena: Allocator, src: []const u8) ![]const u8 {
fn fetchData(self: *Page, arena: Allocator, src: []const u8, base: ?[]const u8) ![]const u8 {
log.debug("starting fetch {s}", .{src});

var buffer: [1024]u8 = undefined;
var b: []u8 = buffer[0..];
const u = try std.Uri.resolve_inplace(self.uri, src, &b);

var res_src = src;

// if a base path is given, we resolve src using base.
if (base) |_base| {
const dir = std.fs.path.dirname(_base);
if (dir) |_dir| {
res_src = try std.fs.path.resolve(arena, &.{ _dir, src });
}
}

const u = try std.Uri.resolve_inplace(self.uri, res_src, &b);

var fetchres = try self.session.loader.get(arena, u);
defer fetchres.deinit();
Expand Down Expand Up @@ -624,7 +649,7 @@ pub const Page = struct {
// received.
fn fetchScript(self: *Page, s: Script) !void {
const arena = self.arena;
const body = try self.fetchData(arena, s.src);
const body = try self.fetchData(arena, s.src, null);
// TODO: change to &self.session.env when
// https://github.com/lightpanda-io/zig-js-runtime/pull/285 lands
try s.eval(arena, self.session.env, body);
Expand Down