From 44251ce8eaa0def807b9867f73ee23adfb539487 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Tue, 9 Jun 2020 13:33:52 +0100 Subject: [PATCH] fix(cli/js/web/worker): Disable relative module specifiers (#5266) --- cli/js/lib.deno.shared_globals.d.ts | 5 +- cli/ops/worker_host.rs | 4 +- cli/tests/subdir/nested_worker.js | 8 +-- cli/tests/workers_round_robin_bench.ts | 5 +- cli/tests/workers_startup_bench.ts | 5 +- cli/tests/workers_test.ts | 87 ++++++++++++++------------ docs/runtime/workers.md | 21 +++++-- 7 files changed, 80 insertions(+), 55 deletions(-) diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts index a93ff1166c..58d25cea4a 100644 --- a/cli/js/lib.deno.shared_globals.d.ts +++ b/cli/js/lib.deno.shared_globals.d.ts @@ -1300,7 +1300,10 @@ declare class Worker extends EventTarget { * * ```ts * // mod.ts - * const worker = new Worker("./deno_worker.ts", { type: "module", deno: true }); + * const worker = new Worker( + * new URL("deno_worker.ts", import.meta.url).href, + * { type: "module", deno: true } + * ); * worker.postMessage({ cmd: "readFile", fileName: "./log.txt" }); * * // deno_worker.ts diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index 0ed700431a..950797352e 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -193,13 +193,11 @@ fn op_create_worker( let mut state = state.borrow_mut(); let global_state = state.global_state.clone(); let permissions = state.permissions.clone(); - let referrer = state.main_module.to_string(); let worker_id = state.next_worker_id; state.next_worker_id += 1; drop(state); - let module_specifier = - ModuleSpecifier::resolve_import(&specifier, &referrer)?; + let module_specifier = ModuleSpecifier::resolve_url(&specifier)?; let worker_name = args_name.unwrap_or_else(|| "".to_string()); let (join_handle, worker_handle) = run_worker_thread( diff --git a/cli/tests/subdir/nested_worker.js b/cli/tests/subdir/nested_worker.js index f5ac23a194..d3801b8c5a 100644 --- a/cli/tests/subdir/nested_worker.js +++ b/cli/tests/subdir/nested_worker.js @@ -1,8 +1,8 @@ // Specifier should be resolved relative to current file -const jsWorker = new Worker("./sibling_worker.js", { - type: "module", - name: "sibling", -}); +const jsWorker = new Worker( + new URL("sibling_worker.js", import.meta.url).href, + { type: "module", name: "sibling" } +); jsWorker.onerror = (_e) => { postMessage({ type: "error" }); diff --git a/cli/tests/workers_round_robin_bench.ts b/cli/tests/workers_round_robin_bench.ts index c7a683459b..d7224b41d3 100644 --- a/cli/tests/workers_round_robin_bench.ts +++ b/cli/tests/workers_round_robin_bench.ts @@ -37,7 +37,10 @@ function handleAsyncMsgFromWorker( async function main(): Promise { const workers: Array<[Map>, Worker]> = []; for (let i = 1; i <= workerCount; ++i) { - const worker = new Worker("./subdir/bench_worker.ts", { type: "module" }); + const worker = new Worker( + new URL("subdir/bench_worker.ts", import.meta.url).href, + { type: "module" } + ); const promise = createResolvable(); worker.onmessage = (e): void => { if (e.data.cmdId === 0) promise.resolve(); diff --git a/cli/tests/workers_startup_bench.ts b/cli/tests/workers_startup_bench.ts index 60c15a4b1d..a25dc8ff7e 100644 --- a/cli/tests/workers_startup_bench.ts +++ b/cli/tests/workers_startup_bench.ts @@ -4,7 +4,10 @@ const workerCount = 50; async function bench(): Promise { const workers: Worker[] = []; for (let i = 1; i <= workerCount; ++i) { - const worker = new Worker("./subdir/bench_worker.ts", { type: "module" }); + const worker = new Worker( + new URL("subdir/bench_worker.ts", import.meta.url).href, + { type: "module" } + ); const promise = new Promise((resolve): void => { worker.onmessage = (e): void => { if (e.data.cmdId === 0) resolve(); diff --git a/cli/tests/workers_test.ts b/cli/tests/workers_test.ts index df2cdf2aa7..feab0f9c27 100644 --- a/cli/tests/workers_test.ts +++ b/cli/tests/workers_test.ts @@ -32,13 +32,14 @@ Deno.test({ fn: async function (): Promise { const promise = createResolvable(); - const jsWorker = new Worker("../tests/subdir/test_worker.js", { - type: "module", - }); - const tsWorker = new Worker("../tests/subdir/test_worker.ts", { - type: "module", - name: "tsWorker", - }); + const jsWorker = new Worker( + new URL("subdir/test_worker.js", import.meta.url).href, + { type: "module" } + ); + const tsWorker = new Worker( + new URL("subdir/test_worker.ts", import.meta.url).href, + { type: "module", name: "tsWorker" } + ); tsWorker.onmessage = (e): void => { assertEquals(e.data, "Hello World"); @@ -67,10 +68,10 @@ Deno.test({ fn: async function (): Promise { const promise = createResolvable(); - const nestedWorker = new Worker("../tests/subdir/nested_worker.js", { - type: "module", - name: "nested", - }); + const nestedWorker = new Worker( + new URL("subdir/nested_worker.js", import.meta.url).href, + { type: "module", name: "nested" } + ); nestedWorker.onmessage = (e): void => { assert(e.data.type !== "error"); @@ -87,9 +88,10 @@ Deno.test({ name: "worker throws when executing", fn: async function (): Promise { const promise = createResolvable(); - const throwingWorker = new Worker("../tests/subdir/throwing_worker.js", { - type: "module", - }); + const throwingWorker = new Worker( + new URL("subdir/throwing_worker.js", import.meta.url).href, + { type: "module" } + ); // eslint-disable-next-line @typescript-eslint/no-explicit-any throwingWorker.onerror = (e: any): void => { @@ -108,9 +110,10 @@ Deno.test({ fn: async function (): Promise { const promise = createResolvable(); - const fetchingWorker = new Worker("../tests/subdir/fetching_worker.js", { - type: "module", - }); + const fetchingWorker = new Worker( + new URL("subdir/fetching_worker.js", import.meta.url).href, + { type: "module" } + ); // eslint-disable-next-line @typescript-eslint/no-explicit-any fetchingWorker.onerror = (e: any): void => { @@ -134,9 +137,10 @@ Deno.test({ fn: async function (): Promise { const promise = createResolvable(); - const busyWorker = new Worker("../tests/subdir/busy_worker.js", { - type: "module", - }); + const busyWorker = new Worker( + new URL("subdir/busy_worker.js", import.meta.url).href, + { type: "module" } + ); let testResult = 0; @@ -166,9 +170,10 @@ Deno.test({ // https://github.com/denoland/deno/issues/4080 const promise = createResolvable(); - const racyWorker = new Worker("../tests/subdir/racy_worker.js", { - type: "module", - }); + const racyWorker = new Worker( + new URL("subdir/racy_worker.js", import.meta.url).href, + { type: "module" } + ); racyWorker.onmessage = (e): void => { assertEquals(e.data.buf.length, 999999); @@ -193,9 +198,10 @@ Deno.test({ const promise1 = createResolvable(); const promise2 = createResolvable(); - const worker = new Worker("../tests/subdir/event_worker.js", { - type: "module", - }); + const worker = new Worker( + new URL("subdir/event_worker.js", import.meta.url).href, + { type: "module" } + ); worker.onmessage = (_e: Event): void => { messageHandlersCalled++; @@ -236,9 +242,10 @@ Deno.test({ fn: async function (): Promise { const promise1 = createResolvable(); - const worker = new Worker("../tests/subdir/event_worker_scope.js", { - type: "module", - }); + const worker = new Worker( + new URL("subdir/event_worker_scope.js", import.meta.url).href, + { type: "module" } + ); worker.onmessage = (e: MessageEvent): void => { const { messageHandlersCalled, errorHandlersCalled } = e.data; @@ -264,13 +271,14 @@ Deno.test({ const promise = createResolvable(); const promise2 = createResolvable(); - const regularWorker = new Worker("../tests/subdir/non_deno_worker.js", { - type: "module", - }); - const denoWorker = new Worker("../tests/subdir/deno_worker.ts", { - type: "module", - deno: true, - }); + const regularWorker = new Worker( + new URL("subdir/non_deno_worker.js", import.meta.url).href, + { type: "module" } + ); + const denoWorker = new Worker( + new URL("subdir/deno_worker.ts", import.meta.url).href, + { type: "module", deno: true } + ); regularWorker.onmessage = (e): void => { assertEquals(e.data, "Hello World"); @@ -295,9 +303,10 @@ Deno.test({ name: "worker with crypto in scope", fn: async function (): Promise { const promise = createResolvable(); - const w = new Worker("../tests/subdir/worker_crypto.js", { - type: "module", - }); + const w = new Worker( + new URL("subdir/worker_crypto.js", import.meta.url).href, + { type: "module" } + ); w.onmessage = (e): void => { assertEquals(e.data, true); promise.resolve(); diff --git a/docs/runtime/workers.md b/docs/runtime/workers.md index 110255b8b6..019df72012 100644 --- a/docs/runtime/workers.md +++ b/docs/runtime/workers.md @@ -7,15 +7,21 @@ Workers can be used to run code on multiple threads. Each instance of `Worker` is run on a separate thread, dedicated only to that worker. Currently Deno supports only `module` type workers; thus it's essential to pass -`type: "module"` option when creating a new worker: +the `type: "module"` option when creating a new worker. + +Relative module specifiers are +[not supported](https://github.com/denoland/deno/issues/5216) at the moment. You +can instead use the `URL` contructor and `import.meta.url` to easily create a +specifier for some nearby script. ```ts // Good -new Worker("./worker.js", { type: "module" }); +new Worker(new URL("worker.js", import.meta.url).href, { type: "module" }); // Bad -new Worker("./worker.js"); -new Worker("./worker.js", { type: "classic" }); +new Worker(new URL("worker.js", import.meta.url).href); +new Worker(new URL("worker.js", import.meta.url).href, { type: "classic" }); +new Worker("./worker.js", { type: "module" }); ``` ### Permissions @@ -28,7 +34,7 @@ For workers using local modules; `--allow-read` permission is required: **main.ts** ```ts -new Worker("./worker.ts", { type: "module" }); +new Worker(new URL("worker.ts", import.meta.url).href, { type: "module" }); ``` **worker.ts** @@ -81,7 +87,10 @@ To add the `Deno` namespace pass `deno: true` option when creating new worker: **main.js** ```ts -const worker = new Worker("./worker.js", { type: "module", deno: true }); +const worker = new Worker(new URL("worker.js", import.meta.url).href, { + type: "module", + deno: true, +}); worker.postMessage({ filename: "./log.txt" }); ```