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.
This commit is contained in:
Karl Seguin
2025-06-23 17:10:54 +08:00
parent bdb2338b5b
commit a01d18ace1
2 changed files with 25 additions and 3 deletions

View File

@@ -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,
});
}

View File

@@ -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 .{