@bigmistqke/worker-proxy
v0.0.13
Published
Improve worker DX with a proxy.
Downloads
84
Readme
@bigmistqke/worker-proxy
Library to improve worker DX, similar to ComLink.
Table of Contents
- Getting Started
- Basic Example
- $transfer Transfer
Transferables - $async Await responses of worker-methods
- $port Expose a WorkerProxy's api to another WorkerProxy
- Callbacks Serialize callbacks to workers
Getting Started
pnpm
pnpm add --save-dev @bigmistqke/vite-plugin-worker-proxy
pnpm add @bigmistqke/worker-proxynpm
npm add --save-dev @bigmistqke/vite-plugin-worker-proxy
npm add @bigmistqke/worker-proxyyarn
yarn add --dev @bigmistqke/vite-plugin-worker-proxy
yarn add --dev @bigmistqke/worker-proxyBasic Example
main.ts
import type Methods from './worker.ts'
// Create WorkerProxy
const worker = createWorkerProxy<Methods>(new Worker('./worker.ts'))
// Call ping-method of worker
worker.ping()
// Call log-method of worker.logger
worker.logger.log('hello', 'bigmistqke')worker.ts
import { type WorkerProps, registerMethods } from '@bigmistqke/worker-proxy'
class Logger {
log(...args: Array<string>) {
console.log(...args)
}
}
// Initialize worker-methods with registerMethods
// Default export types of methods to infer the WorkerProxy's type
export default registerMethods({
logger: new Logger(),
ping() {
console.log('ping')
},
})All non-function values (even deeply nested ones) are stripped out from the types.
// worker.ts
export default registerMethods({
state: 'ignore'
nested: {
state: 'ignore',
ignored: {
state: 'ignore'
},
method() {
return 'not ignored'
}
}
})
// main.ts
import type Methods from './worker.ts'
import Worker from './worker.ts?worker'
const workerProxy = createWorkerProxy<Methods>(new Worker())The resulting type of workerProxy will be:
{
nested: {
method(): string
}
}$async
Await responses of WorkerProxy-methods with worker.$async.method(...)
main.ts
import type Methods from './worker.ts'
const worker = createWorkerProxy<Methods>(new Worker('./worker.ts'))
// Call async version of ask-method
worker.$async.ask('question').then(console.log)worker.ts
import { registerMethods } from '@bigmistqke/worker-proxy'
export default registerMethods({
ask(question: string) {
return 'Answer'
},
})$transfer
Transfer Transferables to/from WorkerProxies with $transfer(...)
main.ts
import { $transfer } from '@bigmistqke/worker-proxy'
import type Methods from './worker.ts'
const worker = createWorkerProxy<Methods>(new Worker('./worker.ts'))
const buffer = new ArrayBuffer()
// Transfer buffer to worker
worker.setBuffer($transfer(buffer, [buffer]))
// Call async version of getBuffer and log awaited results
worker.$async.getBuffer().then(console.log)worker.ts
import { registerMethods } from '@bigmistqke/worker-proxy'
let buffer: ArrayBuffer
export default registerMethods({
setBuffer(_buffer: ArrayBuffer) {
buffer = _buffer
},
getBuffer() {
// Transfer buffer from worker back to main thread
return $transfer(buffer, [buffer])
},
})$port
Expose a WorkerProxy's API to another WorkerProxy with worker.$port() and createWorkerProxy(port):
worker.$port()returns a brandedMessagePort:WorkerProxyPort<T> = MessagePort & { $: T }
createWorkerProxyacceptsWorkerandWorkerProxyPortas argument.- When given a
WorkerProxyPortit infers its type from the branded type.
- When given a
main.ts
import { $transfer } from '@bigmistqke/worker-proxy'
import type HalloMethods from './hallo-worker.ts'
import type GoodbyeMethods from './goodbye-worker.ts'
const halloWorker = createWorkerProxy<HalloMethods>(new Worker('./hallo-worker.ts'))
const goodbyeWorker = createWorkerProxy<GoodbyeMethods>(new Worker('./goodbye-worker.ts'))
// Get a WorkerProxyPort of goodbyeWorker
const port = goodbyeWorker.$port()
// Transfer the WorkerProxyPort to halloWorker
halloWorker.link($transfer(port, [port]))
halloWorker.hallo()hallo-worker.ts
import {
type WorkerProxy,
type WorkerProxyPort,
createWorkerProxy,
registerMethods,
} from '@bigmistqke/worker-proxy'
import type GoodbyeMethods from './goodbye-worker'
let goodbyeWorker: WorkerProxy<GoodbyeMethods>
export default registerMethods({
hallo() {
console.log('hallo')
setTimeout(() => goodbyeWorker.goodbye(), 1000)
},
link(port: WorkerProxyPort<typeof GoodbyeWorkerApi>) {
// Create WorkerProxy from the given WorkerProxyPort
goodbyeWorker = createWorkerProxy(port)
},
})goodbye-worker.ts
import { registerMethods } from '@bigmistqke/worker-proxy'
export default registerMethods({
goodbye() {
console.log('goodbye')
},
})Callbacks
Callbacks are automatically serialized and passed to the worker, but only when they are not embedded within an object/array.
// ✅
worker.callback(console.log)
worker.callback('test', { id: 'user' }, console.log)
// ❌
worker.callback({ log: console.log })
// ❌
worker.callback([console.log])main.ts
import type Methods from './worker.ts'
const worker = createWorkerProxy<Methods>(new Worker('./worker.ts'))
worker.callback(console.log)worker.ts
import { registerMethods } from '@bigmistqke/worker-proxy'
export default registerMethods({
callback(cb: (message: string) => void) {
cb('hallo')
setTimeout(() => cb('world'), 1000)
},
})Manually serialize/deserialize with $callback and $apply
You can also manually serialize and deserialize with $callback and $apply. This can be handy if you prefer explicitness or if you want to pass a callback nested inside object/array.
main.ts
import type Methods from './worker.ts'
import { $callback } from '@bigmistqke/worker-proxy'
const worker = createWorkerProxy<Methods>(new Worker('./worker.ts'))
worker.callback({ log: $callback(console.log) })worker.ts
import { $apply, type Callback, registerMethods } from '@bigmistqke/worker-proxy'
export default registerMethods({
callback({ log }: { log: Callback<(message: string) => void> }) {
$apply(log, 'hallo')
setTimeout(() => $apply(log, 'hallo'), 1000)
},
})