Skip to content

Commit a42a69f

Browse files
committed
Reduce Worker indirection for bundlers
Now that wasm-bindgen has `wasm_bindgen::link_to!`, we can use it to ensure that Worker is emitted alongside the snippet file instead of having to use the snippet file itself as a Worker source. In turn, this allows to use static import of the main module in the Worker, which avoids unnecessary extra code splitting we used to have. Aside from slightly better chunking, this also happens to work around the Parcel issue parcel-bundler/parcel#8727.
1 parent bda6114 commit a42a69f

6 files changed

+61
-73
lines changed

Cargo.lock

+16-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ exclude = [".github"]
1212
repository = "https://github.com/RReverser/wasm-bindgen-rayon"
1313

1414
[dependencies]
15-
wasm-bindgen = "0.2.74"
15+
wasm-bindgen = "0.2.84"
1616
rayon-core = "1.12"
1717
spmc = "0.3.0"
1818
js-sys = "0.3.48"

src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ extern "C" {
5151
fn start_workers(module: JsValue, memory: JsValue, builder: wbg_rayon_PoolBuilder) -> Promise;
5252
}
5353

54+
#[cfg(not(feature = "no-bundler"))]
55+
fn _ensure_worker_emitted() {
56+
// Just ensure that the worker is emitted into the output folder, but don't actually use the URL.
57+
wasm_bindgen::link_to!(module = "/src/workerHelpers.worker.js");
58+
}
59+
5460
#[wasm_bindgen]
5561
impl wbg_rayon_PoolBuilder {
5662
fn new(num_threads: usize) -> Self {

src/workerHelpers.js

+9-54
Original file line numberDiff line numberDiff line change
@@ -18,45 +18,6 @@
1818
// If we didn't take that into the account, we could send much simpler signals
1919
// like just `0` or whatever, but the code would be less resilient.
2020

21-
function waitForMsgType(target, type) {
22-
return new Promise(resolve => {
23-
target.addEventListener('message', function onMsg({ data }) {
24-
if (data == null || data.type !== type) return;
25-
target.removeEventListener('message', onMsg);
26-
resolve(data);
27-
});
28-
});
29-
}
30-
31-
waitForMsgType(self, 'wasm_bindgen_worker_init').then(async data => {
32-
// # Note 1
33-
// Our JS should have been generated in
34-
// `[out-dir]/snippets/wasm-bindgen-rayon-[hash]/workerHelpers.js`,
35-
// resolve the main module via `../../..`.
36-
//
37-
// This might need updating if the generated structure changes on wasm-bindgen
38-
// side ever in the future, but works well with bundlers today. The whole
39-
// point of this crate, after all, is to abstract away unstable features
40-
// and temporary bugs so that you don't need to deal with them in your code.
41-
//
42-
// # Note 2
43-
// This could be a regular import, but then some bundlers complain about
44-
// circular deps.
45-
//
46-
// Dynamic import could be cheap if this file was inlined into the parent,
47-
// which would require us just using `../../..` in `new Worker` below,
48-
// but that doesn't work because wasm-pack unconditionally adds
49-
// "sideEffects":false (see below).
50-
//
51-
// OTOH, even though it can't be inlined, it should be still reasonably
52-
// cheap since the requested file is already in cache (it was loaded by
53-
// the main thread).
54-
const pkg = await import('../../..');
55-
await pkg.default(data.module, data.memory);
56-
postMessage({ type: 'wasm_bindgen_worker_ready' });
57-
pkg.wbg_rayon_start_worker(data.receiver);
58-
});
59-
6021
// Note: this is never used, but necessary to prevent a bug in Firefox
6122
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1702191) where it collects
6223
// Web Workers that have a shared WebAssembly memory with the main thread,
@@ -72,7 +33,6 @@ export async function startWorkers(module, memory, builder) {
7233
}
7334

7435
const workerInit = {
75-
type: 'wasm_bindgen_worker_init',
7636
module,
7737
memory,
7838
receiver: builder.receiver()
@@ -86,21 +46,16 @@ export async function startWorkers(module, memory, builder) {
8646
// way to get asset URLs relative to the module across various bundlers
8747
// and browser, ideally we should switch to `import.meta.resolve`
8848
// once it becomes a standard.
89-
//
90-
// Note: we could use `../../..` as the URL here to inline workerHelpers.js
91-
// into the parent entry instead of creating another split point -
92-
// this would be preferable from optimization perspective -
93-
// however, Webpack then eliminates all message handler code
94-
// because wasm-pack produces "sideEffects":false in package.json
95-
// unconditionally.
96-
//
97-
// The only way to work around that is to have side effect code
98-
// in an entry point such as Worker file itself.
99-
const worker = new Worker(new URL('./workerHelpers.js', import.meta.url), {
100-
type: 'module'
101-
});
49+
const worker = new Worker(
50+
new URL('./workerHelpers.worker.js', import.meta.url),
51+
{
52+
type: 'module'
53+
}
54+
);
10255
worker.postMessage(workerInit);
103-
await waitForMsgType(worker, 'wasm_bindgen_worker_ready');
56+
await new Promise(resolve =>
57+
worker.addEventListener('message', resolve, { once: true })
58+
);
10459
return worker;
10560
})
10661
);

src/workerHelpers.worker.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2022 Google Inc. All Rights Reserved.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
// Note: our JS should have been generated in
15+
// `[out-dir]/snippets/wasm-bindgen-rayon-[hash]/workerHelpers.worker.js`,
16+
// resolve the main module via `../../..`.
17+
//
18+
// This might need updating if the generated structure changes on wasm-bindgen
19+
// side ever in the future, but works well with bundlers today. The whole
20+
// point of this crate, after all, is to abstract away unstable features
21+
// and temporary bugs so that you don't need to deal with them in your code.
22+
import initWbg, { wbg_rayon_start_worker } from '../../../';
23+
24+
onmessage = async ({ data: { module, memory, receiver } }) => {
25+
await initWbg(module, memory);
26+
postMessage(true);
27+
wbg_rayon_start_worker(receiver);
28+
};

test/run-tests.mjs

+1-2
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,4 @@ async function runTest(t) {
6868
test('no-bundler', runTest);
6969
test('rollup', runTest);
7070
test('webpack', runTest);
71-
// Parcel seems broken for now: https://github.com/parcel-bundler/parcel/issues/8727
72-
test.skip('parcel', runTest);
71+
test('parcel', runTest);

0 commit comments

Comments
 (0)