Something went wrong. Try again.
write Deno web servers with Vite
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374import { loadModuleRunner } from './module-runner.ts';import { type InvokeMessage, type ResultMessage, WORKER_CHANNEL, type WorkerChannelMessage,} from './protocol.ts';
/** options for {@link runWorker} */export interface RunWorkerOptions { /** absolute path to the worker module, with any query */ entry: string; /** URL of `vite/module-runner`, matching the `vite` that runs the dev server */ moduleRunner: string;}
/** * evaluates a module through Vite in a worker spawned by the dev server's Deno process. * call before registering message listeners. * * @param options worker options * @returns resolves after module evaluation * @throws when the module fails to load or evaluate */export const runWorker = async ({ entry, moduleRunner }: RunWorkerOptions): Promise<void> => { // buffer messages during async module loading to preserve native worker startup ordering const early: MessageEvent[] = []; const capture = (event: Event) => { if (event instanceof MessageEvent) { event.stopImmediatePropagation(); early.push(event); } }; globalThis.addEventListener('message', capture);
const channel = new BroadcastChannel(WORKER_CHANNEL); const invokes = new Map<string, (result: ResultMessage['result']) => void>();
channel.onmessage = ({ data }: MessageEvent<WorkerChannelMessage>) => { if (data.type === 'result') { const resolve = invokes.get(data.id); if (resolve) { invokes.delete(data.id); resolve(data.result); } } };
const createRunner = await loadModuleRunner(moduleRunner); const runner = createRunner({ transport: { invoke(payload) { const id = crypto.randomUUID(); const { promise, resolve } = Promise.withResolvers<ResultMessage['result']>(); invokes.set(id, resolve);
const message: InvokeMessage = { type: 'invoke', id, payload }; channel.postMessage(message);
return promise; }, }, // re-evaluation would leave existing message listeners registered hmr: false, });
await runner.import(entry);
globalThis.removeEventListener('message', capture); for (const { data, ports } of early) { globalThis.dispatchEvent(new MessageEvent('message', { data, ports: [...ports] })); }};