Skip to content

Commit 44b25d5

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 s
1 parent 6e63094 commit 44b25d5

File tree

7 files changed

+127
-71
lines changed

7 files changed

+127
-71
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: 77 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,39 @@ 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+
self.with_loader = true;
98+
99+
self
100+
}
101+
102+
/// Determines whether the worker will be spawned with
103+
/// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type)
104+
/// set to `module`. `true` by default.
105+
///
106+
/// This option should be un-set if the worker was created with the
107+
/// `--target no-modules` flag of `wasm-bindgen`.
108+
pub fn as_module(&mut self, as_module: bool) -> &mut Self {
109+
self.as_module = as_module;
110+
111+
self
112+
}
113+
114+
/// Spawns a Worker.
115+
pub fn spawn(&self, path: &str) -> WorkerBridge<W>
116+
where
117+
W::Input: Serialize + for<'de> Deserialize<'de>,
118+
W::Output: Serialize + for<'de> Deserialize<'de>,
119+
{
120+
let worker = self.create_worker(path).expect("failed to spawn worker");
121+
122+
self.spawn_inner(worker)
123+
}
124+
108125
fn spawn_inner(&self, worker: DedicatedWorker) -> WorkerBridge<W>
109126
where
110127
W::Input: Serialize + for<'de> Deserialize<'de>,
@@ -159,25 +176,42 @@ where
159176
)
160177
}
161178

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)
179+
fn create_worker(&self, path: &str) -> Option<DedicatedWorker> {
180+
let path = if self.with_loader {
181+
std::borrow::Cow::Borrowed(path)
182+
} else {
183+
let js_shim_url = Url::new_with_base(
184+
path,
185+
&window().location().href().expect("failed to read href."),
186+
)
187+
.expect("failed to create url for javascript entrypoint")
188+
.to_string();
189+
190+
let wasm_url = js_shim_url.replace(".js", "_bg.wasm");
191+
192+
let array = Array::new();
193+
let shim = if self.as_module {
194+
format!(r#"import init from '{js_shim_url}';await init();"#)
195+
} else {
196+
format!(r#"importScripts("{js_shim_url}");wasm_bindgen("{wasm_url}");"#)
197+
};
198+
array.push(&shim.into());
199+
let blob = Blob::new_with_str_sequence_and_options(
200+
&array,
201+
BlobPropertyBag::new().type_("application/javascript"),
202+
)
203+
.unwrap();
204+
let url = Url::create_object_url_with_blob(&blob).unwrap();
205+
std::borrow::Cow::Owned(url)
206+
};
207+
let path = path.as_ref();
208+
209+
if self.as_module {
210+
let mut options = WorkerOptions::new();
211+
options.type_(WorkerType::Module);
212+
DedicatedWorker::new_with_options(path, &options).ok()
213+
} else {
214+
DedicatedWorker::new(path).ok()
215+
}
182216
}
183217
}

crates/worker/src/oneshot/spawner.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,37 @@ 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>,
47-
{
48-
let rx = OneshotBridge::register_callback(&mut self.inner);
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 {
47+
self.inner.with_loader();
4948

50-
let inner = self.inner.spawn(path);
49+
self
50+
}
5151

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

55-
/// Spawns an Oneshot Worker with a loader shim script.
56-
pub fn spawn_with_loader(mut self, loader_path: &str) -> OneshotBridge<N>
64+
/// Spawns a Oneshot Worker.
65+
pub fn spawn(mut self, path: &str) -> OneshotBridge<N>
5766
where
5867
N::Input: Serialize + for<'de> Deserialize<'de>,
5968
N::Output: Serialize + for<'de> Deserialize<'de>,
6069
{
6170
let rx = OneshotBridge::register_callback(&mut self.inner);
6271

63-
let inner = self.inner.spawn_with_loader(loader_path);
72+
let inner = self.inner.spawn(path);
6473

6574
OneshotBridge::new(inner, rx)
6675
}

crates/worker/src/reactor/spawner.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,37 @@ 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>,
48-
{
49-
let rx = ReactorBridge::register_callback(&mut self.inner);
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 {
48+
self.inner.with_loader();
5049

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

53-
ReactorBridge::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+
self.inner.as_module(as_module);
61+
62+
self
5463
}
5564

56-
/// Spawns a Reactor Worker with a loader shim script.
57-
pub fn spawn_with_loader(mut self, loader_path: &str) -> ReactorBridge<R>
65+
/// Spawns a reactor worker.
66+
pub fn spawn(mut self, path: &str) -> ReactorBridge<R>
5867
where
5968
<R::Scope as ReactorScoped>::Input: Serialize + for<'de> Deserialize<'de>,
6069
<R::Scope as ReactorScoped>::Output: Serialize + for<'de> Deserialize<'de>,
6170
{
6271
let rx = ReactorBridge::register_callback(&mut self.inner);
6372

64-
let inner = self.inner.spawn_with_loader(loader_path);
73+
let inner = self.inner.spawn(path);
6574

6675
ReactorBridge::new(inner, rx)
6776
}

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: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ fn main() {
2222
.flatten()
2323
.expect_throw("failed to query root element");
2424

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

2829
spawn_local(async move {
2930
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)