From a01d18ace141321bf2475952e169f9724c132fc4 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Mon, 23 Jun 2025 17:10:54 +0800 Subject: [PATCH] Fix module caching In https://github.com/lightpanda-io/browser/pull/798 module caching was added. This was necessary as the same module loaded multiple time should result in the same v8 module instance. To make this work, modules became cached by their full URL. The full URL of one module was also used to determine the full URL of nested modules (full url + specifier). With inline scripts, the page URL was used as the full URL. While this is correct when resolving nested modules, it's incorrect for caching the module itself. Two inline modules on a page share the same URL, but they aren't the same and should be cached. To fix this, inline modules still inherit the page URL, in order to resolve the correct URL for nested modules, but are themselves never cached. --- src/browser/page.zig | 12 ++++++++++-- src/runtime/js.zig | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/browser/page.zig b/src/browser/page.zig index 3e998e6d..5bbc6b59 100644 --- a/src/browser/page.zig +++ b/src/browser/page.zig @@ -986,12 +986,19 @@ const Script = struct { defer try_catch.deinit(); const src = self.src orelse page.url.raw; + // if self.src is null, then this is an inline script, and it should + // not be cached. + const cacheable = self.src != null; - log.debug(.browser, "executing script", .{ .src = src, .kind = self.kind }); + log.debug(.browser, "executing script", .{ + .src = src, + .kind = self.kind, + .cacheable = cacheable, + }); const result = switch (self.kind) { .javascript => page.main_context.eval(body, src), - .module => page.main_context.module(body, src), + .module => page.main_context.module(body, src, cacheable), }; result catch { @@ -1003,6 +1010,7 @@ const Script = struct { log.warn(.user_script, "eval script", .{ .src = src, .err = msg, + .cacheable = cacheable, }); } diff --git a/src/runtime/js.zig b/src/runtime/js.zig index 6b6bef2c..3cb54271 100644 --- a/src/runtime/js.zig +++ b/src/runtime/js.zig @@ -691,7 +691,11 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { // compile and eval a JS module // It doesn't wait for callbacks execution - pub fn module(self: *JsContext, src: []const u8, url: []const u8) !void { + pub fn module(self: *JsContext, src: []const u8, url: []const u8, cacheable: bool) !void { + if (!cacheable) { + return self.moduleNoCache(src, url); + } + const arena = self.context_arena; const gop = try self.module_cache.getOrPut(arena, url); @@ -718,6 +722,16 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { _ = try m.evaluate(v8_context); } + fn moduleNoCache(self: *JsContext, src: []const u8, url: []const u8) !void { + const m = try compileModule(self.isolate, src, url); + const v8_context = self.v8_context; + if (try m.instantiate(v8_context, resolveModuleCallback) == false) { + return error.ModuleInstantiationError; + } + + _ = try m.evaluate(v8_context); + } + // Wrap a v8.Exception fn createException(self: *const JsContext, e: v8.Value) Exception { return .{