diff --git a/crates/worker/Cargo.toml b/crates/worker/Cargo.toml index d950da18..a988b5ef 100644 --- a/crates/worker/Cargo.toml +++ b/crates/worker/Cargo.toml @@ -39,6 +39,7 @@ features = [ "Url", "Worker", "WorkerOptions", + "WorkerType", ] [features] diff --git a/crates/worker/src/actor/spawner.rs b/crates/worker/src/actor/spawner.rs index fbe0c64f..50d5d2f8 100644 --- a/crates/worker/src/actor/spawner.rs +++ b/crates/worker/src/actor/spawner.rs @@ -8,7 +8,7 @@ use gloo_utils::window; use js_sys::Array; use serde::de::Deserialize; use serde::ser::Serialize; -use web_sys::{Blob, BlobPropertyBag, Url}; +use web_sys::{Blob, BlobPropertyBag, Url, WorkerOptions, WorkerType}; use super::bridge::{CallbackMap, WorkerBridge}; use super::handler_id::HandlerId; @@ -18,28 +18,6 @@ use super::traits::Worker; use super::{Callback, Shared}; use crate::codec::{Bincode, Codec}; -fn create_worker(path: &str) -> DedicatedWorker { - let js_shim_url = Url::new_with_base( - path, - &window().location().href().expect("failed to read href."), - ) - .expect("failed to create url for javascript entrypoint") - .to_string(); - - let wasm_url = js_shim_url.replace(".js", "_bg.wasm"); - - let array = Array::new(); - array.push(&format!(r#"importScripts("{js_shim_url}");wasm_bindgen("{wasm_url}");"#).into()); - let blob = Blob::new_with_str_sequence_and_options( - &array, - BlobPropertyBag::new().type_("application/javascript"), - ) - .unwrap(); - let url = Url::create_object_url_with_blob(&blob).unwrap(); - - DedicatedWorker::new(&url).expect("failed to spawn worker") -} - /// A spawner to create workers. #[derive(Clone)] pub struct WorkerSpawner @@ -49,6 +27,8 @@ where { _marker: PhantomData<(W, CODEC)>, callback: Option>, + with_loader: bool, + as_module: bool, } impl fmt::Debug for WorkerSpawner @@ -81,6 +61,8 @@ where Self { _marker: PhantomData, callback: None, + with_loader: false, + as_module: true, } } @@ -92,6 +74,8 @@ where WorkerSpawner { _marker: PhantomData, callback: self.callback.clone(), + with_loader: self.with_loader, + as_module: self.as_module, } } @@ -105,6 +89,42 @@ where self } + /// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a + /// `path` to a loader shim script (e.g. when using trunk, created by using + /// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types) + /// asset type) and one does not need to be generated. + pub fn with_loader(&mut self) -> &mut Self + { + self.with_loader = true; + + self + } + + /// Determines whether the worker will be spawned with + /// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type) + /// set to `module`. `true` by default. + /// + /// This option should be un-set if the worker was created with the + /// `--target no-modules` flag of `wasm-bindgen`. + pub fn as_module(&mut self, as_module: bool) -> &mut Self + { + self.as_module = as_module; + + self + } + + /// Spawns a Worker. + pub fn spawn(&self, path: &str) -> WorkerBridge + where + W::Input: Serialize + for<'de> Deserialize<'de>, + W::Output: Serialize + for<'de> Deserialize<'de>, + { + let worker = self.create_worker(path) + .expect("failed to spawn worker"); + + self.spawn_inner(worker) + } + fn spawn_inner(&self, worker: DedicatedWorker) -> WorkerBridge where W::Input: Serialize + for<'de> Deserialize<'de>, @@ -159,25 +179,42 @@ where ) } - /// Spawns a Worker. - pub fn spawn(&self, path: &str) -> WorkerBridge - where - W::Input: Serialize + for<'de> Deserialize<'de>, - W::Output: Serialize + for<'de> Deserialize<'de>, - { - let worker = create_worker(path); - - self.spawn_inner(worker) - } - - /// Spawns a Worker with a loader shim script. - pub fn spawn_with_loader(&self, loader_path: &str) -> WorkerBridge - where - W::Input: Serialize + for<'de> Deserialize<'de>, - W::Output: Serialize + for<'de> Deserialize<'de>, - { - let worker = DedicatedWorker::new(loader_path).expect("failed to spawn worker"); - - self.spawn_inner(worker) + fn create_worker(&self, path: &str) -> Option { + let path = if self.with_loader { + std::borrow::Cow::Borrowed(path) + } else { + let js_shim_url = Url::new_with_base( + path, + &window().location().href().expect("failed to read href."), + ) + .expect("failed to create url for javascript entrypoint") + .to_string(); + + let wasm_url = js_shim_url.replace(".js", "_bg.wasm"); + + let array = Array::new(); + let shim = if self.as_module { + format!(r#"import init from '{js_shim_url}';await init();"#) + } else { + format!(r#"importScripts("{js_shim_url}");wasm_bindgen("{wasm_url}");"#) + }; + array.push(&shim.into()); + let blob = Blob::new_with_str_sequence_and_options( + &array, + BlobPropertyBag::new().type_("application/javascript"), + ) + .unwrap(); + let url = Url::create_object_url_with_blob(&blob).unwrap(); + std::borrow::Cow::Owned(url) + }; + let path = path.as_ref(); + + if self.as_module { + let mut options = WorkerOptions::new(); + options.type_(WorkerType::Module); + DedicatedWorker::new_with_options(path, &options).ok() + } else { + DedicatedWorker::new(path).ok() + } } } diff --git a/crates/worker/src/oneshot/spawner.rs b/crates/worker/src/oneshot/spawner.rs index d4cb2402..6cd897d5 100644 --- a/crates/worker/src/oneshot/spawner.rs +++ b/crates/worker/src/oneshot/spawner.rs @@ -39,28 +39,39 @@ where } } - /// Spawns an Oneshot Worker. - pub fn spawn(mut self, path: &str) -> OneshotBridge - where - N::Input: Serialize + for<'de> Deserialize<'de>, - N::Output: Serialize + for<'de> Deserialize<'de>, + /// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a + /// `path` to a loader shim script (e.g. when using trunk, created by using + /// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types) + /// asset type) and one does not need to be generated. + pub fn with_loader(mut self) -> Self { - let rx = OneshotBridge::register_callback(&mut self.inner); + self.inner.with_loader(); - let inner = self.inner.spawn(path); + self + } - OneshotBridge::new(inner, rx) + /// Determines whether the worker will be spawned with + /// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type) + /// set to `module`. `true` by default. + /// + /// This option should be un-set if the worker was created with the + /// `--target no-modules` flag of `wasm-bindgen`. + pub fn as_module(mut self, as_module: bool) -> Self + { + self.inner.as_module(as_module); + + self } - /// Spawns an Oneshot Worker with a loader shim script. - pub fn spawn_with_loader(mut self, loader_path: &str) -> OneshotBridge + /// Spawns a Oneshot Worker. + pub fn spawn(mut self, path: &str) -> OneshotBridge where N::Input: Serialize + for<'de> Deserialize<'de>, N::Output: Serialize + for<'de> Deserialize<'de>, { let rx = OneshotBridge::register_callback(&mut self.inner); - let inner = self.inner.spawn_with_loader(loader_path); + let inner = self.inner.spawn(path); OneshotBridge::new(inner, rx) } diff --git a/crates/worker/src/reactor/spawner.rs b/crates/worker/src/reactor/spawner.rs index 7c4b6a70..9569a89f 100644 --- a/crates/worker/src/reactor/spawner.rs +++ b/crates/worker/src/reactor/spawner.rs @@ -40,28 +40,39 @@ where } } - /// Spawns a reactor worker. - pub fn spawn(mut self, path: &str) -> ReactorBridge - where - ::Input: Serialize + for<'de> Deserialize<'de>, - ::Output: Serialize + for<'de> Deserialize<'de>, + /// Indicates that [`spawn`](WorkerSpawner#method.spawn) should expect a + /// `path` to a loader shim script (e.g. when using trunk, created by using + /// the [`data-loader-shim`](https://trunkrs.dev/assets/#link-asset-types) + /// asset type) and one does not need to be generated. + pub fn with_loader(mut self) -> Self { - let rx = ReactorBridge::register_callback(&mut self.inner); + self.inner.with_loader(); - let inner = self.inner.spawn(path); + self + } - ReactorBridge::new(inner, rx) + /// Determines whether the worker will be spawned with + /// [`options.type`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#type) + /// set to `module`. `true` by default. + /// + /// This option should be un-set if the worker was created with the + /// `--target no-modules` flag of `wasm-bindgen`. + pub fn as_module(mut self, as_module: bool) -> Self + { + self.inner.as_module(as_module); + + self } - /// Spawns a Reactor Worker with a loader shim script. - pub fn spawn_with_loader(mut self, loader_path: &str) -> ReactorBridge + /// Spawns a reactor worker. + pub fn spawn(mut self, path: &str) -> ReactorBridge where ::Input: Serialize + for<'de> Deserialize<'de>, ::Output: Serialize + for<'de> Deserialize<'de>, { let rx = ReactorBridge::register_callback(&mut self.inner); - let inner = self.inner.spawn_with_loader(loader_path); + let inner = self.inner.spawn(path); ReactorBridge::new(inner, rx) } diff --git a/examples/file-hash/src/bin/example_file_hash_app.rs b/examples/file-hash/src/bin/example_file_hash_app.rs index 58046bad..a7bfa538 100644 --- a/examples/file-hash/src/bin/example_file_hash_app.rs +++ b/examples/file-hash/src/bin/example_file_hash_app.rs @@ -23,7 +23,8 @@ fn App() -> Html { result.set(Some(o.hash)); }) .encoding::() - .spawn_with_loader("/example_file_hash_worker_loader.js") + .with_loader() + .spawn("/example_file_hash_worker_loader.js") }, (), ) diff --git a/examples/markdown/src/bin/example_markdown_app.rs b/examples/markdown/src/bin/example_markdown_app.rs index f0f9c0c4..f8b89b64 100644 --- a/examples/markdown/src/bin/example_markdown_app.rs +++ b/examples/markdown/src/bin/example_markdown_app.rs @@ -23,7 +23,7 @@ fn main() { .expect_throw("failed to query root element"); let mut bridge = - MarkdownWorker::spawner().spawn_with_loader("/example_markdown_worker_loader.js"); + MarkdownWorker::spawner().with_loader().spawn("/example_markdown_worker_loader.js"); spawn_local(async move { let content = bridge.run(MARKDOWN_CONTENT.to_owned()).await; diff --git a/examples/prime/src/bin/example_prime_app.rs b/examples/prime/src/bin/example_prime_app.rs index b083589e..c06c4f88 100644 --- a/examples/prime/src/bin/example_prime_app.rs +++ b/examples/prime/src/bin/example_prime_app.rs @@ -25,7 +25,8 @@ fn main() { let started = Rc::new(Cell::new(false)); let (bridge_sink, mut bridge_stream) = Prime::spawner() - .spawn_with_loader("/example_prime_worker_loader.js") + .with_loader() + .spawn("/example_prime_worker_loader.js") .split(); {