Skip to content

Commit 4a9a4cb

Browse files
committed
add CompilationCallback
and load polyfill depending the source content
1 parent 818f454 commit 4a9a4cb

File tree

6 files changed

+91
-9
lines changed

6 files changed

+91
-9
lines changed

src/browser/page.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ pub const Page = struct {
119119
}),
120120
.main_context = undefined,
121121
};
122-
self.main_context = try session.executor.createJsContext(&self.window, self, self, true, Env.GlobalMissingCallback.init(&self.polyfill_loader));
122+
self.main_context = try session.executor.createJsContext(&self.window, self, self, true, .{
123+
.global_callback = Env.GlobalMissingCallback.init(&self.polyfill_loader),
124+
.compilation_callback = Env.CompilationCallback.init(&self.polyfill_loader),
125+
});
123126

124127
// message loop must run only non-test env
125128
if (comptime !builtin.is_test) {

src/browser/polyfill/polyfill.zig

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,23 @@ pub const Loader = struct {
5050
@field(self.done, name) = true;
5151
}
5252

53+
// CompilationCallback implementation
54+
pub fn script(self: *Loader, src: []const u8, _: ?[]const u8, js_context: *Env.JsContext) void {
55+
if (!self.done.webcomponents and containsWebcomponents(src)) {
56+
const source = @import("webcomponents.zig").source;
57+
self.load("webcomponents", source, js_context);
58+
}
59+
}
60+
61+
// CompilationCallback implementation
62+
pub fn module(self: *Loader, src: []const u8, _: []const u8, js_context: *Env.JsContext) void {
63+
if (!self.done.webcomponents and containsWebcomponents(src)) {
64+
const source = @import("webcomponents.zig").source;
65+
self.load("webcomponents", source, js_context);
66+
}
67+
}
68+
69+
// GlobalMissingCallback implementation
5370
pub fn missing(self: *Loader, name: []const u8, js_context: *Env.JsContext) bool {
5471
// Avoid recursive calls during polyfill loading.
5572
if (self.state == .loading) {
@@ -102,4 +119,8 @@ pub const Loader = struct {
102119
if (std.mem.eql(u8, name, "customElements")) return true;
103120
return false;
104121
}
122+
123+
fn containsWebcomponents(src: []const u8) bool {
124+
return std.mem.indexOf(u8, src, " extends ") != null;
125+
}
105126
};

src/browser/polyfill/webcomponents.zig

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ test "Browser.webcomponents" {
1313

1414
try runner.testCases(&.{
1515
.{
16-
\\ window.customElements; // temporarily needed, lazy loading doesn't work!
17-
\\
1816
\\ class LightPanda extends HTMLElement {
1917
\\ constructor() {
2018
\\ super();

src/cdp/cdp.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,10 @@ const IsolatedWorld = struct {
580580
page,
581581
{},
582582
false,
583-
Env.GlobalMissingCallback.init(&self.polyfill_loader),
583+
.{
584+
.global_callback = Env.GlobalMissingCallback.init(&self.polyfill_loader),
585+
.compilation_callback = Env.CompilationCallback.init(&self.polyfill_loader),
586+
},
584587
);
585588
}
586589
};

src/runtime/js.zig

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,25 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
364364
self.context_arena.deinit();
365365
}
366366

367+
pub const CreateJsContextOpt = struct {
368+
global_callback: ?GlobalMissingCallback = null,
369+
compilation_callback: ?CompilationCallback = null,
370+
};
371+
367372
// Only the top JsContext in the Main ExecutionWorld should hold a handle_scope.
368373
// A v8.HandleScope is like an arena. Once created, any "Local" that
369374
// v8 creates will be released (or at least, releasable by the v8 GC)
370375
// when the handle_scope is freed.
371376
// We also maintain our own "context_arena" which allows us to have
372377
// all page related memory easily managed.
373-
pub fn createJsContext(self: *ExecutionWorld, global: anytype, state: State, module_loader: anytype, enter: bool, global_callback: ?GlobalMissingCallback) !*JsContext {
378+
pub fn createJsContext(
379+
self: *ExecutionWorld,
380+
global: anytype,
381+
state: State,
382+
module_loader: anytype,
383+
enter: bool,
384+
opt: CreateJsContextOpt,
385+
) !*JsContext {
374386
std.debug.assert(self.js_context == null);
375387

376388
const ModuleLoader = switch (@typeInfo(@TypeOf(module_loader))) {
@@ -401,7 +413,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
401413

402414
// Configure the missing property callback on the global
403415
// object.
404-
if (global_callback != null) {
416+
if (opt.global_callback != null) {
405417
const configuration = v8.NamedPropertyHandlerConfiguration{
406418
.getter = struct {
407419
fn callback(c_name: ?*const v8.C_Name, raw_info: ?*const v8.C_PropertyCallbackInfo) callconv(.c) u8 {
@@ -505,7 +517,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
505517
.ptr = safe_module_loader,
506518
.func = ModuleLoader.fetchModuleSource,
507519
},
508-
.global_callback = global_callback,
520+
.global_callback = opt.global_callback,
521+
.compilation_callback = opt.compilation_callback,
509522
};
510523

511524
var js_context = &self.js_context.?;
@@ -658,9 +671,12 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
658671
// necessary to lookup/store the dependent module in the module_cache.
659672
module_identifier: std.AutoHashMapUnmanaged(u32, []const u8) = .empty,
660673

661-
// Global callback is called on missing property.
674+
// Global callback is called when a property is missing on the
675+
// global object.
662676
global_callback: ?GlobalMissingCallback = null,
663677

678+
compilation_callback: ?CompilationCallback = null,
679+
664680
const ModuleLoader = struct {
665681
ptr: *anyopaque,
666682
func: *const fn (ptr: *anyopaque, specifier: []const u8) anyerror!?[]const u8,
@@ -747,6 +763,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
747763
}
748764

749765
pub fn exec(self: *JsContext, src: []const u8, name: ?[]const u8) !Value {
766+
if (self.compilation_callback) |cbk| cbk.script(src, name, self);
767+
750768
const isolate = self.isolate;
751769
const v8_context = self.v8_context;
752770

@@ -770,6 +788,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
770788
// compile and eval a JS module
771789
// It doesn't wait for callbacks execution
772790
pub fn module(self: *JsContext, src: []const u8, url: []const u8, cacheable: bool) !void {
791+
if (self.compilation_callback) |cbk| cbk.module(src, url, self);
792+
773793
if (!cacheable) {
774794
return self.moduleNoCache(src, url);
775795
}
@@ -2604,6 +2624,43 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
26042624
return self.missingFn(self.ptr, name, ctx);
26052625
}
26062626
};
2627+
2628+
// CompilationCallback called before script and module compilation.
2629+
pub const CompilationCallback = struct {
2630+
ptr: *anyopaque,
2631+
scriptFn: *const fn (ptr: *anyopaque, source: []const u8, name: ?[]const u8, ctx: *JsContext) void,
2632+
moduleFn: *const fn (ptr: *anyopaque, source: []const u8, url: []const u8, ctx: *JsContext) void,
2633+
2634+
pub fn init(ptr: anytype) CompilationCallback {
2635+
const T = @TypeOf(ptr);
2636+
const ptr_info = @typeInfo(T);
2637+
2638+
const gen = struct {
2639+
pub fn script(pointer: *anyopaque, source: []const u8, name: ?[]const u8, ctx: *JsContext) void {
2640+
const self: T = @ptrCast(@alignCast(pointer));
2641+
return ptr_info.pointer.child.script(self, source, name, ctx);
2642+
}
2643+
pub fn module(pointer: *anyopaque, source: []const u8, url: []const u8, ctx: *JsContext) void {
2644+
const self: T = @ptrCast(@alignCast(pointer));
2645+
return ptr_info.pointer.child.module(self, source, url, ctx);
2646+
}
2647+
};
2648+
2649+
return .{
2650+
.ptr = ptr,
2651+
.scriptFn = gen.script,
2652+
.moduleFn = gen.module,
2653+
};
2654+
}
2655+
2656+
pub fn script(self: CompilationCallback, source: []const u8, name: ?[]const u8, ctx: *JsContext) void {
2657+
return self.scriptFn(self.ptr, source, name, ctx);
2658+
}
2659+
2660+
pub fn module(self: CompilationCallback, source: []const u8, url: []const u8, ctx: *JsContext) void {
2661+
return self.moduleFn(self.ptr, source, url, ctx);
2662+
}
2663+
};
26072664
};
26082665
}
26092666

src/runtime/testing.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub fn Runner(comptime State: type, comptime Global: type, comptime types: anyty
5353
state,
5454
{},
5555
true,
56-
null,
56+
.{},
5757
);
5858
return self;
5959
}

0 commit comments

Comments
 (0)