Skip to content

Commit

Permalink
Add vite project to test demo build
Browse files Browse the repository at this point in the history
  • Loading branch information
sisou committed Dec 2, 2024
1 parent 370e633 commit c85af7d
Show file tree
Hide file tree
Showing 26 changed files with 2,270 additions and 2 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
target
pkg
out
node_modules/
test-results/
Expand Down
3 changes: 2 additions & 1 deletion demo/run.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
wasm-pack build --target web
rm -rf pkg
wasm-pack build --target web --no-opt
python3 -m http.server 8000
24 changes: 24 additions & 0 deletions vite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
3 changes: 3 additions & 0 deletions vite/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}
5 changes: 5 additions & 0 deletions vite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Vue 3 + TypeScript + Vite

This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
14 changes: 14 additions & 0 deletions vite/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<script type="module" src="/index.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
23 changes: 23 additions & 0 deletions vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "vite",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"vite-plugin-top-level-await": "^1.4.4",
"vite-plugin-wasm": "^3.3.0",
"vue": "^3.5.13",
"wasmworker": "link:../demo/pkg"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "~5.6.2",
"vite": "^6.0.1",
"vue-tsc": "^2.1.10"
}
}
8 changes: 8 additions & 0 deletions vite/public/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import init, { runWorker, runPool, runParMap } from '/pkg/wasmworker_demo.js'

init().then(() => {
console.log('index.js initialized')
window.runWorker = runWorker
window.runPool = runPool
window.runParMap = runParMap
})
136 changes: 136 additions & 0 deletions vite/public/pkg/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# wasmworker
`wasmworker` is a library that provides easy access to parallelization on web targets when compiled to WebAssembly using [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen).
In contrast to many other libraries like [wasm-bindgen-rayon](https://github.com/RReverser/wasm-bindgen-rayon), this library does not require SharedArrayBuffer support.

- [Usage](#usage)
- [Setting up](#setting-up)
- [Outsourcing tasks](#outsourcing-tasks)
- [WebWorker](#webworker)
- [WebWorkerPool](#webworkerpool)
- [Iterator extension](#iterator-extension)
- [Feature detection](#feature-detection)
- [FAQ](#faq)

## Usage
The library consists of two crates:
- `wasmworker`: The main crate that also offers access to the webworker, as well as the worker pool and iterator extensions.
- `wasmworker-proc-macro`: This crate is needed to expose functions towards the web workers via the `#[webworker_fn]` macro.

### Setting up
To use this library, include both dependencies to your `Cargo.toml`.

```toml
[dependencies]
wasmworker = "0.1"
wasmworker-proc-macro = "0.1"
```

The `wasmworker` crate comes with a default feature called `serde`, which allows running any function on a web worker under the following two conditions:
1. The function takes a single argument, which implements `serde::Serialize + serde::Deserialize<'de>`.
2. The return type implements `serde::Serialize + serde::Deserialize<'de>`.

Without the `serde` feature, only functions with the type `fn(Box<[u8]>) -> Box<[u8]>` can be run on a worker.
This is useful for users that do not want a direct serde dependency. Internally, the library always uses serde, though.

You can then start using the library without further setup.
If you plan on using the global `WebWorkerPool` (using the iterator extensions or `worker_pool()`), you can *optionally* configure this pool:
```rust
// Importing it publicly will also expose the function on the JavaScript side.
// You can instantiate the pool both via Rust and JS.
pub use wasmworker::{init_worker_pool, WorkerPoolOptions};

async fn startup() {
init_worker_pool(WorkerPoolOptions {
num_workers: Some(2), // Default is navigator.hardwareConcurrency
..Default::default()
}).await;
}
```

### Outsourcing tasks
The library offers three ways of outsourcing function calls onto concurrent workers:
1. `WebWorker`: a single worker, to which tasks can be queued to.
2. `WebWorkerPool`: a pool of multiple workers, to which tasks are distributed.
3. `par_map`: an extension to regular iterators, which allows to execute a function on every element of the iterator in parallel using the default worker pool.

All approaches require the functions that should be executed to be annotated with the `#[webworker_fn]` macro.
This macro ensures that the functions are available to the web worker instances:

```rust,ignore
use serde::{Deserialize, Serialize};
use wasmworker_proc_macro::webworker_fn;
/// An arbitrary type that is (de)serializable.
#[derive(Serialize, Deserialize)]
pub struct VecType(Vec<u8>);
/// A sort function on a custom type.
#[webworker_fn]
pub fn sort_vec(mut v: VecType) -> VecType {
v.0.sort();
v
}
```

Whenever we want to execute a function, we need to pass the corresponding `WebWorkerFn` object to the worker.
This object describes the function to the worker and can be safely obtained via the `webworker!()` macro:

```rust,ignore
use wasmworker::webworker;
let ww_sort = webworker!(sort_vec);
```

#### WebWorker
We can instantiate our own workers and run functions on them:
```rust,ignore
use wasmworker::{webworker, WebWorker};
let worker = WebWorker::new(None).await;
let res = worker.run(webworker!(sort_vec), &VecType(vec![5, 2, 8])).await;
assert_eq!(res.0, vec![2, 5, 8]);
```

#### WebWorkerPool
Most of the time, we probably want to schedule tasks to a pool of workers, though.
The default worker pool is instantiated on first use and can be configured using `init_worker_pool()` as described above.
It uses a round-robin scheduler (with the second option being a load based scheduler), a number of `navigator.hardwareConcurrency` separate workers, and the default inferred path.

```rust,ignore
use wasmworker::{webworker, worker_pool};
let worker_pool = worker_pool().await;
let res = worker_pool.run(webworker!(sort_vec), &VecType(vec![5, 2, 8])).await;
assert_eq!(res.0, vec![2, 5, 8]);
```

#### Iterator extension
Inspired by [Rayon](https://github.com/rayon-rs/rayon), this library also offers a (much simpler and less powerful) method for iterators.
This functionality automatically parallelizes a map operation on the default worker pool.

```rust,ignore
use wasmworker::iter_ext::IteratorExt;
let some_vec = vec![
VecType(vec![5, 2, 8]),
// ...
];
let res: Vec<VecType> = some_vec.iter().par_map(webworker!(sort_vec)).await;
```

## FAQ
1. _Why would you not want to use SharedArrayBuffers?_

The use of SharedArrayBuffers requires cross-origin policy headers to be set, which is not possible in every environment.
Moreover, most libraries that rely on SharedArrayBuffers, also require a nightly version of Rust at the moment.
An important goal of this library is to remove these requirements.

2. _Which `wasm-bindgen` targets are supported?_

So far, this library has only been tested with `--target web`.
Other targets seem to generally be problematic in that the wasm glue is inaccessible or paths are not correct.
Both the `Worker` and `WebWorkerPool` have an option to set a custom path, which should make it possible to support other targets dynamically, though.

3. _Can I use bundlers?_

The usage of bundlers has not been officially tested. This might be added in the future.
30 changes: 30 additions & 0 deletions vite/public/pkg/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "wasmworker-demo",
"type": "module",
"collaborators": [
"Pascal Berrang <[email protected]>"
],
"description": "Dispatching tasks to a WebWorker without `SharedArrayBuffers`.",
"version": "0.1.0",
"license": "MIT OR Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/paberr/wasmworker"
},
"files": [
"wasmworker_demo_bg.wasm",
"wasmworker_demo.js",
"wasmworker_demo.d.ts"
],
"main": "wasmworker_demo.js",
"homepage": "https://github.com/paberr/wasmworker",
"types": "wasmworker_demo.d.ts",
"sideEffects": [
"./snippets/*"
],
"keywords": [
"webworker",
"parallelism",
"wasm"
]
}
Loading

0 comments on commit c85af7d

Please sign in to comment.