Web Workers
Type-safe workers are easy to use. They just use Vite's built-in worker-loader.
import type { Incoming, Outgoing } from "foo.worker"
import Worker from "foo.worker?worker"
const worker = new Worker()
// type-safe postMessage
function post<I extends Incoming["type"]>(
type: I,
data: Extract<Incoming, { type: I }>["data"],
transfer?: Transferable[]
) {
worker.postMessage({ type, data }, { transfer })
}
// type-safe onmessage
worker.addEventListener("message", ({ data: event }: MessageEvent<Outgoing>) => {
...
})
/// <reference lib="webworker" />
export type Incoming = { id: number } & (
| { type: "add"; data: { a: number; b: number } }
| { type: "sub"; data: { a: number; b: number } }
)
export type Outgoing = { id: number } & (
| { type: "add"; data: { result: number } }
| { type: "sub"; data: { result: number } }
)
self.onmessage = (e: MessageEvent<Incoming>) => handleMessage(e.data)
function post<I extends Incoming>(
sourceEvent: I,
data: Extract<Outgoing, { type: I["type"] }>["data"],
transfer?: Transferable[]
) {
self.postMessage({ id: sourceEvent.id, type: sourceEvent.type, data }, { transfer })
}
function handleMessage(event: Incoming) {
switch (event.type) {
case "add":
post(event, { result: event.data.a + event.data.b })
break
case "sub":
post(event, { result: event.data.a - event.data.b })
break
}
}