-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: test
ModuleRunnerTransport
invoke
API
- Loading branch information
1 parent
ccee3d7
commit 8c6af6e
Showing
2 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
packages/vite/src/node/ssr/runtime/__tests__/fixtures/worker.invoke.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// @ts-check | ||
|
||
import { BroadcastChannel, parentPort } from 'node:worker_threads' | ||
import { fileURLToPath } from 'node:url' | ||
import { ESModulesEvaluator, ModuleRunner } from 'vite/module-runner' | ||
|
||
if (!parentPort) { | ||
throw new Error('File "worker.js" must be run in a worker thread') | ||
} | ||
|
||
/** @type {import('vite/module-runner').ModuleRunnerTransport} */ | ||
const transport = { | ||
async invoke(/** @type {import('vite').HotPayload} */ event) { | ||
const hotPayloadData = event['data'] | ||
|
||
const id = hotPayloadData['data'][0] | ||
|
||
if (id === 'test_invalid_error') { | ||
return { | ||
error: 'a string instead of an error' | ||
} | ||
} | ||
|
||
if (id !== 'virtual:invoke-default-string') { | ||
return { | ||
error: new Error(`error, module not found: ${id}`) | ||
} | ||
} | ||
|
||
return { | ||
result: { | ||
"code": "__vite_ssr_exports__.default = 'hello invoke world'", | ||
"id": "\0virtual:invoke-default-string", | ||
} | ||
}; | ||
}, | ||
} | ||
|
||
const runner = new ModuleRunner( | ||
{ | ||
root: fileURLToPath(new URL('./', import.meta.url)), | ||
transport, | ||
hmr: false, | ||
}, | ||
new ESModulesEvaluator(), | ||
) | ||
|
||
const channel = new BroadcastChannel('vite-worker') | ||
channel.onmessage = async (message) => { | ||
try { | ||
const mod = await runner.import(message.data.id) | ||
channel.postMessage({ result: mod.default }) | ||
} catch (e) { | ||
channel.postMessage({ error: e.stack }) | ||
} | ||
} | ||
parentPort.postMessage('ready') |
140 changes: 140 additions & 0 deletions
140
packages/vite/src/node/ssr/runtime/__tests__/server-worker-runner.invoke.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { BroadcastChannel, Worker } from 'node:worker_threads' | ||
import { afterAll, beforeAll, describe, expect, it } from 'vitest' | ||
import type { HotChannel, HotChannelListener, HotPayload } from 'vite' | ||
import { DevEnvironment } from '../../..' | ||
import { type ViteDevServer, createServer } from '../../../server' | ||
|
||
const createWorkerTransport = (w: Worker): HotChannel => { | ||
const handlerToWorkerListener = new WeakMap< | ||
HotChannelListener, | ||
(value: HotPayload) => void | ||
>() | ||
|
||
return { | ||
send: (data) => w.postMessage(data), | ||
on: (event: string, handler: HotChannelListener) => { | ||
if (event === 'connection') return | ||
|
||
const listener = (value: HotPayload) => { | ||
if (value.type === 'custom' && value.event === event) { | ||
const client = { | ||
send(payload: HotPayload) { | ||
w.postMessage(payload) | ||
}, | ||
} | ||
handler(value.data, client) | ||
} | ||
} | ||
handlerToWorkerListener.set(handler, listener) | ||
w.on('message', listener) | ||
}, | ||
off: (event, handler: HotChannelListener) => { | ||
if (event === 'connection') return | ||
const listener = handlerToWorkerListener.get(handler) | ||
if (listener) { | ||
w.off('message', listener) | ||
handlerToWorkerListener.delete(handler) | ||
} | ||
}, | ||
} | ||
} | ||
|
||
describe('running module runner inside a worker and using the ModuleRunnerTransport#invoke API', () => { | ||
let worker: Worker | ||
let server: ViteDevServer | ||
|
||
beforeAll(async () => { | ||
worker = new Worker( | ||
new URL('./fixtures/worker.invoke.mjs', import.meta.url), | ||
{ | ||
stdout: true, | ||
}, | ||
) | ||
await new Promise<void>((resolve, reject) => { | ||
worker.on('message', () => resolve()) | ||
worker.on('error', reject) | ||
}) | ||
server = await createServer({ | ||
root: __dirname, | ||
logLevel: 'error', | ||
server: { | ||
middlewareMode: true, | ||
watch: null, | ||
hmr: { | ||
port: 9610, | ||
}, | ||
}, | ||
environments: { | ||
worker: { | ||
dev: { | ||
createEnvironment: (name, config) => { | ||
return new DevEnvironment(name, config, { | ||
hot: false, | ||
transport: createWorkerTransport(worker), | ||
}) | ||
}, | ||
}, | ||
}, | ||
}, | ||
}) | ||
}) | ||
|
||
afterAll(() => { | ||
server.close() | ||
worker.terminate() | ||
}) | ||
|
||
it('correctly runs ssr code', async () => { | ||
const channel = new BroadcastChannel('vite-worker') | ||
return new Promise<void>((resolve, reject) => { | ||
channel.onmessage = (event) => { | ||
try { | ||
expect((event as MessageEvent).data).toEqual({ | ||
result: 'hello invoke world', | ||
}) | ||
} catch (e) { | ||
reject(e) | ||
} finally { | ||
resolve() | ||
} | ||
} | ||
channel.postMessage({ id: 'virtual:invoke-default-string' }) | ||
}) | ||
}) | ||
|
||
it('correctly triggers an error', async () => { | ||
const channel = new BroadcastChannel('vite-worker') | ||
return new Promise<void>((resolve, reject) => { | ||
channel.onmessage = (event) => { | ||
try { | ||
expect((event as MessageEvent).data.error).toContain( | ||
'Error: error, module not found: test_error', | ||
) | ||
} catch (e) { | ||
reject(e) | ||
} finally { | ||
resolve() | ||
} | ||
} | ||
channel.postMessage({ id: 'test_error' }) | ||
}) | ||
}) | ||
|
||
it('correctly triggers an unknown error', async () => { | ||
const channel = new BroadcastChannel('vite-worker') | ||
return new Promise<void>((resolve, reject) => { | ||
channel.onmessage = (event) => { | ||
try { | ||
expect((event as MessageEvent).data.error).toContain( | ||
'Error: Unknown invoke error', | ||
) | ||
} catch (e) { | ||
reject(e) | ||
} finally { | ||
resolve() | ||
} | ||
} | ||
channel.postMessage({ id: 'test_invalid_error' }) | ||
}) | ||
}) | ||
}) |