Guides
Comlink-like API
Build a Comlink-like wrap/expose layer on top of Comctx.
This guide shows how to build a Comlink-like wrap/expose layer on top of Comctx.
Use this pattern if you prefer the Comlink style API, or if you are migrating from Comlink and want to keep a similar developer experience.
The example below is inspired by @wordpress/worker-threads.
comlink.ts
import {
defineProxy,
type Adapter,
type OnMessage,
type SendMessage
} from 'comctx'
class WorkerInjectAdapter implements Adapter {
constructor(private worker: Worker) {}
sendMessage: SendMessage = (message, transfer) => {
this.worker.postMessage(message, transfer)
}
onMessage: OnMessage = (callback) => {
const handler = (event: MessageEvent) => callback(event.data)
this.worker.addEventListener('message', handler)
return () => this.worker.removeEventListener('message', handler)
}
}
class WorkerProvideAdapter implements Adapter {
sendMessage: SendMessage = (message, transfer) => {
self.postMessage(message, transfer)
}
onMessage: OnMessage = (callback) => {
const handler = (event: MessageEvent) => callback(event.data)
self.addEventListener('message', handler)
return () => self.removeEventListener('message', handler)
}
}
export function wrap<T extends object>(worker: Worker) {
const [, inject] = defineProxy(() => ({}) as T, {
namespace: '__comlink_like__',
heartbeatCheck: false,
transfer: true
})
return inject(new WorkerInjectAdapter(worker))
}
export function expose<T extends object>(target: T) {
const [provide] = defineProxy(() => target, {
namespace: '__comlink_like__',
heartbeatCheck: false,
transfer: true
})
provide(new WorkerProvideAdapter())
}worker.ts
import { expose } from './comlink'
const api = {
async increment(value: number) {
return value + 1
}
}
expose(api)
export type WorkerAPI = typeof apimain.ts
import { wrap } from './comlink'
import type { WorkerAPI } from './worker'
const worker = new Worker(new URL('./worker.ts', import.meta.url), {
type: 'module'
})
const api = wrap<WorkerAPI>(worker)
console.log(await api.increment(1))How it works
This wrapper keeps the Comctx transport model, but exposes a smaller API surface:
wrap(worker)creates an Injector-side proxyexpose(api)registers the Provider-side implementation- both sides use the same
namespace heartbeatCheck: falsedisables the provider readiness check, which is useful when the Provider side may not be ready immediately, such as when worker code or iframe content loads asynchronouslytransfer: trueenables transferable object support
When to use this pattern
Use this pattern when:
- you prefer a Comlink-style
wrap/exposeAPI - you are migrating from Comlink
- you want a thin compatibility layer without changing the underlying Comctx model