diff --git a/build.zig.zon b/build.zig.zon index 529dfee1..f0ede008 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -13,8 +13,8 @@ .hash = "tigerbeetle_io-0.0.0-ViLgxpyRBAB5BMfIcj3KMXfbJzwARs9uSl8aRy2OXULd", }, .v8 = .{ - .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/23718cdb99aaa45105d0a7e0ca22587bf77d3b5f.tar.gz", - .hash = "v8-0.0.0-xddH68m2AwDf42Qp2Udz4wTMVH8p71si7yLlUoZkPeEz", + .url = "https://github.com/lightpanda-io/zig-v8-fork/archive/46ddf8c0a2861a4e5717e6f8d0d81a17e42fa0c9.tar.gz", + .hash = "v8-0.0.0-xddH6865AwDiDnu-HjMsqm9wXvP9OZOh_4clh_67iQsq", }, //.v8 = .{ .path = "../zig-v8-fork" }, //.tigerbeetle_io = .{ .path = "../tigerbeetle-io" }, diff --git a/src/browser/page.zig b/src/browser/page.zig index 6dc99f33..e8f92216 100644 --- a/src/browser/page.zig +++ b/src/browser/page.zig @@ -1001,7 +1001,11 @@ const Script = struct { try_catch.init(page.main_context); defer try_catch.deinit(); - const src = self.src orelse page.url.raw; + const src: []const u8 = blk: { + const s = self.src orelse break :blk page.url.raw; + break :blk try URL.stitch(page.arena, s, page.url.raw, .{.alloc = .if_needed}); + }; + // if self.src is null, then this is an inline script, and it should // not be cached. const cacheable = self.src != null; diff --git a/src/main.zig b/src/main.zig index 3139ff6b..f54c90fb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -580,7 +580,7 @@ fn parseCommonArg( var it = std.mem.splitScalar(u8, str, ','); while (it.next()) |part| { try arr.append(allocator, std.meta.stringToEnum(log.Scope, part) orelse { - log.fatal(.app, "invalid option choice", .{ .arg = "--log_scope_filter", .value = part }); + log.fatal(.app, "invalid option choice", .{ .arg = "--log_filter_scopes", .value = part }); return false; }); } diff --git a/src/runtime/js.zig b/src/runtime/js.zig index 9539b2be..25cc3141 100644 --- a/src/runtime/js.zig +++ b/src/runtime/js.zig @@ -197,6 +197,16 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { isolate.enter(); errdefer isolate.exit(); + isolate.setHostInitializeImportMetaObjectCallback(struct { + fn callback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_meta: ?*v8.C_Value) callconv(.C) void { + const v8_context = v8.Context{.handle = c_context.?}; + const js_context: *JsContext = @ptrFromInt(v8_context.getEmbedderData(1).castTo(v8.BigInt).getUint64()); + js_context.initializeImportMeta(v8.Module{.handle = c_module.?}, v8.Object{.handle = c_meta.?}) catch |err| { + log.err(.js, "import meta", .{ .err = err }); + }; + } + }.callback); + var temp_scope: v8.HandleScope = undefined; v8.HandleScope.init(&temp_scope, isolate); defer temp_scope.deinit(); @@ -726,13 +736,15 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { fn moduleNoCache(self: *JsContext, src: []const u8, url: []const u8) !void { const m = try compileModule(self.isolate, src, url); + + const arena = self.context_arena; + const owned_url = try arena.dupe(u8, url); + try self.module_identifier.putNoClobber(arena, m.getIdentityHash(), owned_url); + const v8_context = self.v8_context; if (try m.instantiate(v8_context, resolveModuleCallback) == false) { return error.ModuleInstantiationError; } - const arena = self.context_arena; - const owned_url = try arena.dupe(u8, url); - try self.module_identifier.putNoClobber(arena, m.getIdentityHash(), owned_url); _ = try m.evaluate(v8_context); } @@ -1279,6 +1291,20 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { return self.createException(js_value); } + fn initializeImportMeta(self: *JsContext, m: v8.Module, meta: v8.Object) !void { + const url = self.module_identifier.get(m.getIdentityHash()) orelse { + // Shouldn't be possible. + return error.UnknownModuleReferrer; + }; + + const js_key = v8.String.initUtf8(self.isolate, "url"); + const js_value = try self.zigValueToJs(url); + const res = meta.defineOwnProperty(self.v8_context, js_key.toName(), js_value, 0) orelse false; + if (!res) { + return error.FailedToSet; + } + } + // Callback from V8, asking us to load a module. The "specifier" is // the src of the module to load. fn resolveModuleCallback( @@ -1335,7 +1361,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { try_catch.init(self); defer try_catch.deinit(); - const m = compileModule(self.isolate, source, specifier) catch |err| { + const m = compileModule(self.isolate, source, normalized_specifier) catch |err| { log.warn(.js, "compile resolved module", .{ .specifier = specifier, .stack = try_catch.stack(self.call_arena) catch null, diff --git a/src/url.zig b/src/url.zig index fa2dad8a..43c61946 100644 --- a/src/url.zig +++ b/src/url.zig @@ -111,7 +111,7 @@ pub const URL = struct { return src; } - var normalized_src = if (std.mem.startsWith(u8, src, "/")) src[1..] else src; + var normalized_src = src; while (std.mem.startsWith(u8, normalized_src, "./")) { normalized_src = normalized_src[2..]; } @@ -131,6 +131,13 @@ pub const URL = struct { } }; + if (normalized_src[0] == '/') { + if (std.mem.indexOfScalarPos(u8, base, protocol_end, '/')) |pos| { + return std.fmt.allocPrint(allocator, "{s}{s}", .{ base[0..pos], normalized_src }); + } + // not sure what to do here...error? Just let it fallthrough for now. + } + if (std.mem.lastIndexOfScalar(u8, base[protocol_end..], '/')) |index| { const last_slash_pos = index + protocol_end; if (last_slash_pos == base.len - 1) { @@ -257,6 +264,16 @@ test "URL: Stitching Base & Src URLs (No Ending Slash)" { try testing.expectString("https://lightpanda.io/something.js", result); } +test "URL: Stitching Base with absolute src" { + const allocator = testing.allocator; + + const base = "https://lightpanda.io/hello"; + const src = "/abc/something.js"; + const result = try URL.stitch(allocator, src, base, .{}); + defer allocator.free(result); + try testing.expectString("https://lightpanda.io/abc/something.js", result); +} + test "URL: Stiching Base & Src URLs (Both Local)" { const allocator = testing.allocator;