Web Workers allow offloading expensive computations on a background thread in browsers.
vite
supports creating Web Workers with new Worker
.
const url = new URL("./feed.ts", import.meta.url); // 👈 Add `import.meta.url` for Vite
const newWorker = new Worker(url, { type: "module" });
Since Web Workers are processes outside of React, this is a valid case of using useEffect
to create and interact with a worker.
Make sure to call
terminate()
inuseEffect
clean up function.
Interacting with a worker consists of two operations:
- Sending messages (
postMessage
) - Receiving messages (
onmessage
)
onmessage
can be made type-safe by passing the expected messages inside MessageEvent
(e.g. MessageEvent<WorkerResponse>
).
postMessage
accepts any
as parameter. We can make it type-safe as well by using satisfies
to enforce the value provided:
worker.current.postMessage({
type: "feed.get",
source: "https://www.sandromaglione.com/feed",
} satisfies WorkerMessage);
The worker script implements onmessage
as well. Inside it you can perform any (expensive) computation, and then send back a message with the result to the main thread (postMessage
).
Inside vite.config.ts
you can specify the output format of the worker bundle (e.g. "es"
):
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()],
worker: { format: "es" },
});
Make sure to also specify type: "module"
when creating the Worker
instance (otherwise you will get the following error: SyntaxError: Cannot use import statement outside a module
):
const url = new URL("./feed.ts", import.meta.url);
const newWorker = new Worker(url,
{ type: "module" }
);