feat(runtime): support classic workers for internal testing (#11338)

This commit implements classic workers, but only when the `--enable-testing-features-do-not-use` flag is provided. This change is not user facing. Classic workers are used extensively in WPT tests. The classic workers do not support loading from disk, and do not support TypeScript.

Co-authored-by: Luca Casonato <hello@lcas.dev>
This commit is contained in:
Andreu Botella 2021-08-16 14:29:54 +02:00 committed by GitHub
parent d1d2388d7f
commit ddbb7b83f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 485 additions and 15 deletions

View file

@ -7,7 +7,6 @@
ArrayIsArray,
ArrayPrototypeMap,
Error,
Uint8Array,
StringPrototypeStartsWith,
String,
SymbolIterator,
@ -28,6 +27,7 @@
useDenoNamespace,
permissions,
name,
workerType,
) {
return core.opSync("op_create_worker", {
hasSourceCode,
@ -36,6 +36,7 @@
sourceCode,
specifier,
useDenoNamespace,
workerType,
});
}
@ -183,20 +184,12 @@
}
}
if (type !== "module") {
throw new Error(
'Not yet implemented: only "module" type workers are supported',
);
}
this.#name = name;
const hasSourceCode = false;
const sourceCode = core.decode(new Uint8Array());
const workerType = webidl.converters["WorkerType"](type);
if (
StringPrototypeStartsWith(specifier, "./") ||
StringPrototypeStartsWith(specifier, "../") ||
StringPrototypeStartsWith(specifier, "/") || type == "classic"
StringPrototypeStartsWith(specifier, "/") || workerType === "classic"
) {
const baseUrl = getLocationHref();
if (baseUrl != null) {
@ -204,6 +197,16 @@
}
}
this.#name = name;
let hasSourceCode, sourceCode;
if (workerType === "classic") {
hasSourceCode = true;
sourceCode = `importScripts("#");`;
} else {
hasSourceCode = false;
sourceCode = "";
}
const id = createWorker(
specifier,
hasSourceCode,
@ -213,6 +216,7 @@
? null
: parsePermissions(workerDenoAttributes.permissions),
options?.name,
workerType,
);
this.#id = id;
this.#pollControl();
@ -344,6 +348,11 @@
defineEventHandler(Worker.prototype, "message");
defineEventHandler(Worker.prototype, "messageerror");
webidl.converters["WorkerType"] = webidl.createEnumConverter("WorkerType", [
"classic",
"module",
]);
window.__bootstrap.worker = {
parsePermissions,
Worker,

View file

@ -8,6 +8,7 @@ delete Object.prototype.__proto__;
((window) => {
const core = Deno.core;
const {
ArrayPrototypeMap,
Error,
FunctionPrototypeCall,
FunctionPrototypeBind,
@ -164,6 +165,44 @@ delete Object.prototype.__proto__;
}
}
let loadedMainWorkerScript = false;
function importScripts(...urls) {
if (core.opSync("op_worker_get_type") === "module") {
throw new TypeError("Can't import scripts in a module worker.");
}
const baseUrl = location.getLocationHref();
const parsedUrls = ArrayPrototypeMap(urls, (scriptUrl) => {
try {
return new url.URL(scriptUrl, baseUrl ?? undefined).href;
} catch {
throw new domException.DOMException(
"Failed to parse URL.",
"SyntaxError",
);
}
});
// A classic worker's main script has looser MIME type checks than any
// imported scripts, so we use `loadedMainWorkerScript` to distinguish them.
// TODO(andreubotella) Refactor worker creation so the main script isn't
// loaded with `importScripts()`.
const scripts = core.opSync(
"op_worker_sync_fetch",
parsedUrls,
!loadedMainWorkerScript,
);
loadedMainWorkerScript = true;
for (const { url, script } of scripts) {
const err = core.evalContext(script, url)[1];
if (err !== null) {
throw err.thrown;
}
}
}
function opMainModule() {
return core.opSync("op_main_module");
}
@ -597,6 +636,13 @@ delete Object.prototype.__proto__;
}
ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties);
ObjectDefineProperties(globalThis, { name: util.readOnly(name) });
if (runtimeOptions.enableTestingFeaturesFlag) {
ObjectDefineProperty(
globalThis,
"importScripts",
util.writable(importScripts),
);
}
ObjectSetPrototypeOf(globalThis, DedicatedWorkerGlobalScope.prototype);
const consoleFromDeno = globalThis.console;