Skip to content

Commit 2b207f1

Browse files
committed
Add option to spawn workers as a module
This would allow creating workers with the `--target web` flag, alleviating the current missing features described [here](https://rustwasm.github.io/wasm-bindgen/examples/without-a-bundler.html?highlight=no-modules#using-the-older---target-no-modules) Update spawner.rs f Update spawner.rs Update mod.rs
1 parent 6e63094 commit 2b207f1

File tree

7 files changed

+130
-68
lines changed

7 files changed

+130
-68
lines changed

crates/worker/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ features = [
3939
"Url",
4040
"Worker",
4141
"WorkerOptions",
42+
"WorkerType",
4243
]
4344

4445
[features]

crates/worker/src/actor/spawner.rs

Lines changed: 80 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use gloo_utils::window;
88
use js_sys::Array;
99
use serde::de::Deserialize;
1010
use serde::ser::Serialize;
11-
use web_sys::{Blob, BlobPropertyBag, Url};
11+
use web_sys::{Blob, BlobPropertyBag, Url, WorkerOptions, WorkerType};
1212

1313
use super::bridge::{CallbackMap, WorkerBridge};
1414
use super::handler_id::HandlerId;
@@ -18,28 +18,6 @@ use super::traits::Worker;
1818
use super::{Callback, Shared};
1919
use crate::codec::{Bincode, Codec};
2020

21-
fn create_worker(path: &str) -> DedicatedWorker {
22-
let js_shim_url = Url::new_with_base(
23-
path,
24-
&window().location().href().expect("failed to read href."),
25-
)
26-
.expect("failed to create url for javascript entrypoint")
27-
.to_string();
28-
29-
let wasm_url = js_shim_url.replace(".js", "_bg.wasm");
30-
31-
let array = Array::new();
32-
array.push(&format!(r#"importScripts("{js_shim_url}");wasm_bindgen("{wasm_url}");"#).into());
33-
let blob = Blob::new_with_str_sequence_and_options(
34-
&array,
35-
BlobPropertyBag::new().type_("application/javascript"),
36-
)
37-
.unwrap();
38-
let url = Url::create_object_url_with_blob(&blob).unwrap();
39-
40-
DedicatedWorker::new(&url).expect("failed to spawn worker")
41-
}
42-
4321
/// A spawner to create workers.
4422
#[derive(Clone)]
4523
pub struct WorkerSpawner<W, CODEC = Bincode>
@@ -49,6 +27,8 @@ where
4927
{
5028
_marker: PhantomData<(W, CODEC)>,
5129
callback: Option<Callback<W::Output>>,
30+
with_loader: bool,
31+
as_module: bool,
5232
}
5333

5434
impl<W, CODEC> fmt::Debug for WorkerSpawner<W, CODEC>
@@ -81,6 +61,8 @@ where
8161
Self {
8262
_marker: PhantomData,
8363
callback: None,
64+
with_loader: false,
65+
as_module: true,
8466
}
8567
}
8668

@@ -92,6 +74,8 @@ where
9274
WorkerSpawner {
9375
_marker: PhantomData,
9476
callback: self.callback.clone(),
77+
with_loader: self.with_loader,
78+
as_module: self.as_module,
9579
}
9680
}
9781

@@ -105,6 +89,42 @@ where
10589
self
10690
}
10791

92+
/// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a
93+
/// `path` to a loader shim script (e.g. when using trunk, created by using
94+
/// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types)
95+
/// asset type) and one does not need to be generated.
96+
pub fn with_loader(&mut self) -> &mut Self
97+
{
98+
self.with_loader = true;
99+
100+
self
101+
}
102+
103+
/// Determines whether the worker will be spawned with
104+
/// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)
105+
/// set to `module`. `true` by default.
106+
///
107+
/// This option should be un-set if the worker was created with the
108+
/// `--target no-modules` flag of `wasm-bindgen`.
109+
pub fn as_module(&mut self, as_module: bool) -> &mut Self
110+
{
111+
self.as_module = as_module;
112+
113+
self
114+
}
115+
116+
/// Spawns a Worker.
117+
pub fn spawn(&self, path: &str) -> WorkerBridge<W>
118+
where
119+
W::Input: Serialize + for<'de> Deserialize<'de>,
120+
W::Output: Serialize + for<'de> Deserialize<'de>,
121+
{
122+
let worker = self.create_worker(path)
123+
.expect("failed to spawn worker");
124+
125+
self.spawn_inner(worker)
126+
}
127+
108128
fn spawn_inner(&self, worker: DedicatedWorker) -> WorkerBridge<W>
109129
where
110130
W::Input: Serialize + for<'de> Deserialize<'de>,
@@ -159,25 +179,42 @@ where
159179
)
160180
}
161181

162-
/// Spawns a Worker.
163-
pub fn spawn(&self, path: &str) -> WorkerBridge<W>
164-
where
165-
W::Input: Serialize + for<'de> Deserialize<'de>,
166-
W::Output: Serialize + for<'de> Deserialize<'de>,
167-
{
168-
let worker = create_worker(path);
169-
170-
self.spawn_inner(worker)
171-
}
172-
173-
/// Spawns a Worker with a loader shim script.
174-
pub fn spawn_with_loader(&self, loader_path: &str) -> WorkerBridge<W>
175-
where
176-
W::Input: Serialize + for<'de> Deserialize<'de>,
177-
W::Output: Serialize + for<'de> Deserialize<'de>,
178-
{
179-
let worker = DedicatedWorker::new(loader_path).expect("failed to spawn worker");
180-
181-
self.spawn_inner(worker)
182+
fn create_worker(&self, path: &str) -> Option<DedicatedWorker> {
183+
let path = if self.with_loader {
184+
std::borrow::Cow::Borrowed(path)
185+
} else {
186+
let js_shim_url = Url::new_with_base(
187+
path,
188+
&window().location().href().expect("failed to read href."),
189+
)
190+
.expect("failed to create url for javascript entrypoint")
191+
.to_string();
192+
193+
let wasm_url = js_shim_url.replace(".js", "_bg.wasm");
194+
195+
let array = Array::new();
196+
let shim = if self.as_module {
197+
format!(r#"import init from '{js_shim_url}';await init();"#)
198+
} else {
199+
format!(r#"importScripts("{js_shim_url}");wasm_bindgen("{wasm_url}");"#)
200+
};
201+
array.push(&shim.into());
202+
let blob = Blob::new_with_str_sequence_and_options(
203+
&array,
204+
BlobPropertyBag::new().type_("application/javascript"),
205+
)
206+
.unwrap();
207+
let url = Url::create_object_url_with_blob(&blob).unwrap();
208+
std::borrow::Cow::Owned(url)
209+
};
210+
let path = path.as_ref();
211+
212+
if self.as_module {
213+
let mut options = WorkerOptions::new();
214+
options.type_(WorkerType::Module);
215+
DedicatedWorker::new_with_options(path, &options).ok()
216+
} else {
217+
DedicatedWorker::new(path).ok()
218+
}
182219
}
183220
}

crates/worker/src/oneshot/spawner.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,39 @@ where
3939
}
4040
}
4141

42-
/// Spawns an Oneshot Worker.
43-
pub fn spawn(mut self, path: &str) -> OneshotBridge<N>
44-
where
45-
N::Input: Serialize + for<'de> Deserialize<'de>,
46-
N::Output: Serialize + for<'de> Deserialize<'de>,
42+
/// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a
43+
/// `path` to a loader shim script (e.g. when using trunk, created by using
44+
/// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types)
45+
/// asset type) and one does not need to be generated.
46+
pub fn with_loader(mut self) -> Self
4747
{
48-
let rx = OneshotBridge::register_callback(&mut self.inner);
48+
self.inner.with_loader();
4949

50-
let inner = self.inner.spawn(path);
50+
self
51+
}
5152

52-
OneshotBridge::new(inner, rx)
53+
/// Determines whether the worker will be spawned with
54+
/// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)
55+
/// set to `module`. `true` by default.
56+
///
57+
/// This option should be un-set if the worker was created with the
58+
/// `--target no-modules` flag of `wasm-bindgen`.
59+
pub fn as_module(mut self, as_module: bool) -> Self
60+
{
61+
self.inner.as_module(as_module);
62+
63+
self
5364
}
5465

55-
/// Spawns an Oneshot Worker with a loader shim script.
56-
pub fn spawn_with_loader(mut self, loader_path: &str) -> OneshotBridge<N>
66+
/// Spawns a Oneshot Worker.
67+
pub fn spawn(mut self, path: &str) -> OneshotBridge<N>
5768
where
5869
N::Input: Serialize + for<'de> Deserialize<'de>,
5970
N::Output: Serialize + for<'de> Deserialize<'de>,
6071
{
6172
let rx = OneshotBridge::register_callback(&mut self.inner);
6273

63-
let inner = self.inner.spawn_with_loader(loader_path);
74+
let inner = self.inner.spawn(path);
6475

6576
OneshotBridge::new(inner, rx)
6677
}

crates/worker/src/reactor/spawner.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,39 @@ where
4040
}
4141
}
4242

43-
/// Spawns a reactor worker.
44-
pub fn spawn(mut self, path: &str) -> ReactorBridge<R>
45-
where
46-
<R::Scope as ReactorScoped>::Input: Serialize + for<'de> Deserialize<'de>,
47-
<R::Scope as ReactorScoped>::Output: Serialize + for<'de> Deserialize<'de>,
43+
/// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a
44+
/// `path` to a loader shim script (e.g. when using trunk, created by using
45+
/// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types)
46+
/// asset type) and one does not need to be generated.
47+
pub fn with_loader(mut self) -> Self
4848
{
49-
let rx = ReactorBridge::register_callback(&mut self.inner);
49+
self.inner.with_loader();
5050

51-
let inner = self.inner.spawn(path);
51+
self
52+
}
5253

53-
ReactorBridge::new(inner, rx)
54+
/// Determines whether the worker will be spawned with
55+
/// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)
56+
/// set to `module`. `true` by default.
57+
///
58+
/// This option should be un-set if the worker was created with the
59+
/// `--target no-modules` flag of `wasm-bindgen`.
60+
pub fn as_module(mut self, as_module: bool) -> Self
61+
{
62+
self.inner.as_module(as_module);
63+
64+
self
5465
}
5566

56-
/// Spawns a Reactor Worker with a loader shim script.
57-
pub fn spawn_with_loader(mut self, loader_path: &str) -> ReactorBridge<R>
67+
/// Spawns a reactor worker.
68+
pub fn spawn(mut self, path: &str) -> ReactorBridge<R>
5869
where
5970
<R::Scope as ReactorScoped>::Input: Serialize + for<'de> Deserialize<'de>,
6071
<R::Scope as ReactorScoped>::Output: Serialize + for<'de> Deserialize<'de>,
6172
{
6273
let rx = ReactorBridge::register_callback(&mut self.inner);
6374

64-
let inner = self.inner.spawn_with_loader(loader_path);
75+
let inner = self.inner.spawn(path);
6576

6677
ReactorBridge::new(inner, rx)
6778
}

examples/file-hash/src/bin/example_file_hash_app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ fn App() -> Html {
2323
result.set(Some(o.hash));
2424
})
2525
.encoding::<TransferrableCodec>()
26-
.spawn_with_loader("/example_file_hash_worker_loader.js")
26+
.with_loader()
27+
.spawn("/example_file_hash_worker_loader.js")
2728
},
2829
(),
2930
)

examples/markdown/src/bin/example_markdown_app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn main() {
2323
.expect_throw("failed to query root element");
2424

2525
let mut bridge =
26-
MarkdownWorker::spawner().spawn_with_loader("/example_markdown_worker_loader.js");
26+
MarkdownWorker::spawner().with_loader().spawn("/example_markdown_worker_loader.js");
2727

2828
spawn_local(async move {
2929
let content = bridge.run(MARKDOWN_CONTENT.to_owned()).await;

examples/prime/src/bin/example_prime_app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ fn main() {
2525
let started = Rc::new(Cell::new(false));
2626

2727
let (bridge_sink, mut bridge_stream) = Prime::spawner()
28-
.spawn_with_loader("/example_prime_worker_loader.js")
28+
.with_loader()
29+
.spawn("/example_prime_worker_loader.js")
2930
.split();
3031

3132
{

0 commit comments

Comments
 (0)