diff options
author | Andreu Botella <abb@randomunok.com> | 2021-08-16 14:29:54 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-16 14:29:54 +0200 |
commit | ddbb7b83f2c483e354f425dfb70dbab494b05ea5 (patch) | |
tree | fa84f5607395773284e331fe32f2b86b59f02a5d /runtime/js | |
parent | d1d2388d7f1a09fd2469b356f00b6b361269a0b7 (diff) |
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>
Diffstat (limited to 'runtime/js')
-rw-r--r-- | runtime/js/11_workers.js | 31 | ||||
-rw-r--r-- | runtime/js/99_main.js | 46 |
2 files changed, 66 insertions, 11 deletions
diff --git a/runtime/js/11_workers.js b/runtime/js/11_workers.js index b5a8a9d0c..2f9413119 100644 --- a/runtime/js/11_workers.js +++ b/runtime/js/11_workers.js @@ -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, diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js index 6d5599e71..b1f7d1473 100644 --- a/runtime/js/99_main.js +++ b/runtime/js/99_main.js @@ -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; |