mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 01:25:53 -04:00
Merge pull request #2616 from lightpanda-io/worker_module
Support for "module" type workers.
This commit is contained in:
@@ -620,7 +620,7 @@ test "Env: Worker context " {
|
||||
const frame = try session.createPage();
|
||||
defer session.removePage();
|
||||
|
||||
const worker = try @import("../webapi/Worker.zig").init("http://localhost:9582/src/browser/tests/testing.js", frame);
|
||||
const worker = try @import("../webapi/Worker.zig").init("http://localhost:9582/src/browser/tests/testing.js", null, frame);
|
||||
|
||||
var ls: js.Local.Scope = undefined;
|
||||
worker._worker_scope.js.localScope(&ls);
|
||||
|
||||
25
src/browser/tests/worker/module-worker.js
Normal file
25
src/browser/tests/worker/module-worker.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// A module worker (`new Worker(url, { type: "module" })`). Unlike a classic
|
||||
// worker, the entry script may use top-level static `import`/`export`, and
|
||||
// `importScripts()` is not supported (it throws a TypeError).
|
||||
import { baseValue } from './modules/base.js';
|
||||
import { importedValue, localValue } from './modules/importer.js';
|
||||
|
||||
export const exported = 'top-level-export-ok';
|
||||
|
||||
let importScriptsError = null;
|
||||
try {
|
||||
importScripts('./import-script1.js');
|
||||
} catch (e) {
|
||||
importScriptsError = e.constructor.name;
|
||||
}
|
||||
|
||||
onmessage = function (event) {
|
||||
postMessage({
|
||||
echo: event.data,
|
||||
baseValue: baseValue,
|
||||
importedValue: importedValue,
|
||||
localValue: localValue,
|
||||
importScriptsError: importScriptsError,
|
||||
from: 'module-worker',
|
||||
});
|
||||
};
|
||||
@@ -380,6 +380,29 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="worker_module_type" type=module>
|
||||
// A module-type worker: its entry script uses top-level static import (only
|
||||
// valid in module workers), and importScripts() throws a TypeError.
|
||||
{
|
||||
const state = await testing.async();
|
||||
const worker = new Worker('./module-worker.js', { type: 'module' });
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
state.resolve(event.data);
|
||||
};
|
||||
worker.postMessage({ greeting: 'to-module' });
|
||||
|
||||
await state.done((response) => {
|
||||
testing.expectEqual('to-module', response.echo.greeting);
|
||||
testing.expectEqual('module-worker', response.from);
|
||||
testing.expectEqual('from-base', response.baseValue);
|
||||
testing.expectEqual('from-base', response.importedValue);
|
||||
testing.expectEqual('local', response.localValue);
|
||||
testing.expectEqual('TypeError', response.importScriptsError);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="worker_from_blob_url" type=module>
|
||||
// A blob: worker resolves its initial script through the HTTP client's
|
||||
// synthetic-scheme path against the frame's blob registry, like any URL.
|
||||
|
||||
@@ -36,6 +36,12 @@ const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||
|
||||
const Worker = @This();
|
||||
|
||||
pub const WorkerType = enum {
|
||||
classic,
|
||||
module,
|
||||
pub const js_enum_from_string = true;
|
||||
};
|
||||
|
||||
// used by HttpClient when generating notification
|
||||
// Ultimately used by CDP to generate request/loader ids.
|
||||
_frame_id: u32,
|
||||
@@ -47,6 +53,7 @@ _arena: Allocator,
|
||||
_worker_scope: *WorkerGlobalScope,
|
||||
|
||||
_url: [:0]const u8,
|
||||
_type: WorkerType = .classic,
|
||||
_script_loaded: bool = false,
|
||||
_script_buffer: std.ArrayList(u8) = .empty,
|
||||
_http_response: ?HttpClient.Response = null,
|
||||
@@ -56,7 +63,11 @@ _on_error: ?js.Function.Global = null,
|
||||
_on_message: ?js.Function.Global = null,
|
||||
_on_messageerror: ?js.Function.Global = null,
|
||||
|
||||
pub fn init(url: []const u8, frame: *Frame) !*Worker {
|
||||
const WorkerOptions = struct {
|
||||
type: WorkerType = .classic,
|
||||
};
|
||||
|
||||
pub fn init(url: []const u8, options: ?WorkerOptions, frame: *Frame) !*Worker {
|
||||
const session = frame._session;
|
||||
|
||||
const arena = try session.getArena(.large, "Worker");
|
||||
@@ -68,6 +79,7 @@ pub fn init(url: []const u8, frame: *Frame) !*Worker {
|
||||
._proto = undefined,
|
||||
._frame = frame,
|
||||
._url = resolved_url,
|
||||
._type = if (options) |o| o.type else .classic,
|
||||
._worker_scope = undefined,
|
||||
._frame_id = session.nextFrameId(),
|
||||
._loader_id = session.nextLoaderId(),
|
||||
@@ -195,12 +207,24 @@ fn loadInitialScript(self: *Worker, script: []const u8) !void {
|
||||
try_catch.init(&ls.local);
|
||||
defer try_catch.deinit();
|
||||
|
||||
_ = ls.local.eval(script, self._url) catch |err| {
|
||||
const caught = try_catch.caughtOrError(self._arena, err);
|
||||
log.err(.browser, "worker script error", .{ .url = self._url, .caught = caught });
|
||||
self.fireErrorEvent(caught.exception orelse @errorName(err), null);
|
||||
return;
|
||||
};
|
||||
// Classic workers evaluate the entry script as a classic script; module
|
||||
// workers (`new Worker(url, { type: "module" })`) instantiate it as a
|
||||
// module so top-level `import`/`export` work. Static imports load
|
||||
// synchronously through ScriptManagerBase (client.tick sync_wait).
|
||||
switch (self._type) {
|
||||
.classic => _ = ls.local.eval(script, self._url) catch |err| {
|
||||
const caught = try_catch.caughtOrError(self._arena, err);
|
||||
log.err(.browser, "worker script error", .{ .url = self._url, .caught = caught });
|
||||
self.fireErrorEvent(caught.exception orelse @errorName(err), null);
|
||||
return;
|
||||
},
|
||||
.module => self._worker_scope.js.module(false, &ls.local, script, self._url, true) catch |err| {
|
||||
const caught = try_catch.caughtOrError(self._arena, err);
|
||||
log.err(.browser, "worker module error", .{ .url = self._url, .caught = caught });
|
||||
self.fireErrorEvent(caught.exception orelse @errorName(err), null);
|
||||
return;
|
||||
},
|
||||
}
|
||||
|
||||
ls.local.runMacrotasks();
|
||||
}
|
||||
|
||||
@@ -430,6 +430,12 @@ pub fn close(self: *WorkerGlobalScope) void {
|
||||
}
|
||||
|
||||
pub fn importScripts(self: *WorkerGlobalScope, urls: []const [:0]const u8) !void {
|
||||
if (self._worker._type == .module) {
|
||||
// not allowed to be called when the worker type is module (scripts should
|
||||
// use actual imports).
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const session = self._session;
|
||||
const arena = try session.getArena(.large, "importScript");
|
||||
defer session.releaseArena(arena);
|
||||
|
||||
Reference in New Issue
Block a user