From 7c8d9a68cff029342d54c0f46a6a9c02ea3b2af3 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 18 Dec 2024 19:15:05 +0000 Subject: [PATCH] Revert "Reduce Worker indirection for bundlers" This reverts commit a42a69fcebf13faba2319b7b607e610084935292. Unfortunately, this removes a useful optimisation, but is necessary to workaround the semver breakage caused by https://github.com/rustwasm/wasm-bindgen/issues/4159. --- src/lib.rs | 7 ---- src/workerHelpers.js | 70 ++++++++++++++++++++++++++++++++----- src/workerHelpers.worker.js | 28 --------------- 3 files changed, 61 insertions(+), 44 deletions(-) delete mode 100644 src/workerHelpers.worker.js diff --git a/src/lib.rs b/src/lib.rs index 8bbc72f..c217a07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,13 +52,6 @@ extern "C" { fn start_workers(module: JsValue, memory: JsValue, builder: wbg_rayon_PoolBuilder) -> Promise; } -#[cfg(not(feature = "no-bundler"))] -#[allow(unused_must_use)] -fn _ensure_worker_emitted() { - // Just ensure that the worker is emitted into the output folder, but don't actually use the URL. - wasm_bindgen::link_to!(module = "/src/workerHelpers.worker.js"); -} - #[wasm_bindgen] impl wbg_rayon_PoolBuilder { fn new(num_threads: usize) -> Self { diff --git a/src/workerHelpers.js b/src/workerHelpers.js index 7160c7f..3bc740e 100644 --- a/src/workerHelpers.js +++ b/src/workerHelpers.js @@ -11,6 +11,52 @@ * limitations under the License. */ +// Note: we use `wasm_bindgen_worker_`-prefixed message types to make sure +// we can handle bundling into other files, which might happen to have their +// own `postMessage`/`onmessage` communication channels. +// +// If we didn't take that into the account, we could send much simpler signals +// like just `0` or whatever, but the code would be less resilient. + +function waitForMsgType(target, type) { + return new Promise(resolve => { + target.addEventListener('message', function onMsg({ data }) { + if (data?.type !== type) return; + target.removeEventListener('message', onMsg); + resolve(data); + }); + }); +} + +waitForMsgType(self, 'wasm_bindgen_worker_init').then(async data => { + // # Note 1 + // Our JS should have been generated in + // `[out-dir]/snippets/wasm-bindgen-rayon-[hash]/workerHelpers.js`, + // resolve the main module via `../../..`. + // + // This might need updating if the generated structure changes on wasm-bindgen + // side ever in the future, but works well with bundlers today. The whole + // point of this crate, after all, is to abstract away unstable features + // and temporary bugs so that you don't need to deal with them in your code. + // + // # Note 2 + // This could be a regular import, but then some bundlers complain about + // circular deps. + // + // Dynamic import could be cheap if this file was inlined into the parent, + // which would require us just using `../../..` in `new Worker` below, + // but that doesn't work because wasm-pack unconditionally adds + // "sideEffects":false (see below). + // + // OTOH, even though it can't be inlined, it should be still reasonably + // cheap since the requested file is already in cache (it was loaded by + // the main thread). + const pkg = await import('../../..'); + await pkg.default(data.module, data.memory); + postMessage({ type: 'wasm_bindgen_worker_ready' }); + pkg.wbg_rayon_start_worker(data.receiver); +}); + // Note: this is never used, but necessary to prevent a bug in Firefox // (https://bugzilla.mozilla.org/show_bug.cgi?id=1702191) where it collects // Web Workers that have a shared WebAssembly memory with the main thread, @@ -26,6 +72,7 @@ export async function startWorkers(module, memory, builder) { } const workerInit = { + type: 'wasm_bindgen_worker_init', module, memory, receiver: builder.receiver() @@ -39,16 +86,21 @@ export async function startWorkers(module, memory, builder) { // way to get asset URLs relative to the module across various bundlers // and browser, ideally we should switch to `import.meta.resolve` // once it becomes a standard. - const worker = new Worker( - new URL('./workerHelpers.worker.js', import.meta.url), - { - type: 'module' - } - ); + // + // Note: we could use `../../..` as the URL here to inline workerHelpers.js + // into the parent entry instead of creating another split point - + // this would be preferable from optimization perspective - + // however, Webpack then eliminates all message handler code + // because wasm-pack produces "sideEffects":false in package.json + // unconditionally. + // + // The only way to work around that is to have side effect code + // in an entry point such as Worker file itself. + const worker = new Worker(new URL('./workerHelpers.js', import.meta.url), { + type: 'module' + }); worker.postMessage(workerInit); - await new Promise(resolve => - worker.addEventListener('message', resolve, { once: true }) - ); + await waitForMsgType(worker, 'wasm_bindgen_worker_ready'); return worker; }) ); diff --git a/src/workerHelpers.worker.js b/src/workerHelpers.worker.js deleted file mode 100644 index 1667eb7..0000000 --- a/src/workerHelpers.worker.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 Google Inc. All Rights Reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Note: our JS should have been generated in -// `[out-dir]/snippets/wasm-bindgen-rayon-[hash]/workerHelpers.worker.js`, -// resolve the main module via `../../..`. -// -// This might need updating if the generated structure changes on wasm-bindgen -// side ever in the future, but works well with bundlers today. The whole -// point of this crate, after all, is to abstract away unstable features -// and temporary bugs so that you don't need to deal with them in your code. -import initWbg, { wbg_rayon_start_worker } from '../../../'; - -onmessage = async ({ data: { receiver, ...initData } }) => { - await initWbg(initData); - postMessage(true); - wbg_rayon_start_worker(receiver); -};