diff --git a/packages/vitest/src/integrations/env/index.ts b/packages/vitest/src/integrations/env/index.ts index 07d6fbf530e80..4a6025eadd11a 100644 --- a/packages/vitest/src/integrations/env/index.ts +++ b/packages/vitest/src/integrations/env/index.ts @@ -1,6 +1,7 @@ -import { pathToFileURL } from 'node:url' import { normalize, resolve } from 'pathe' import { resolvePath } from 'mlly' +import { ViteNodeRunner } from 'vite-node/client' +import type { ViteNodeRunnerOptions } from 'vite-node' import type { BuiltinEnvironment, VitestEnvironment } from '../../types/config' import type { Environment } from '../../types' import node from './node' @@ -35,13 +36,26 @@ export function getEnvPackageName(env: VitestEnvironment) { return `vitest-environment-${env}` } -export async function loadEnvironment(name: VitestEnvironment, root: string): Promise { +const _loaders = new Map() + +export async function createEnvironmentLoader(options: ViteNodeRunnerOptions) { + if (!_loaders.has(options.root)) { + const loader = new ViteNodeRunner(options) + await loader.executeId('/@vite/env') + _loaders.set(options.root, loader) + } + return _loaders.get(options.root)! +} + +export async function loadEnvironment(name: VitestEnvironment, options: ViteNodeRunnerOptions): Promise { if (isBuiltinEnvironment(name)) return environments[name] + const loader = await createEnvironmentLoader(options) + const root = loader.root const packageId = name[0] === '.' || name[0] === '/' ? resolve(root, name) : await resolvePath(`vitest-environment-${name}`, { url: [root] }) ?? resolve(root, name) - const pkg = await import(pathToFileURL(normalize(packageId)).href) + const pkg = await loader.executeId(normalize(packageId)) if (!pkg || !pkg.default || typeof pkg.default !== 'object') { throw new TypeError( `Environment "${name}" is not a valid environment. ` diff --git a/packages/vitest/src/runtime/child.ts b/packages/vitest/src/runtime/child.ts index 5bdf6cd984ad7..d3df2af516acc 100644 --- a/packages/vitest/src/runtime/child.ts +++ b/packages/vitest/src/runtime/child.ts @@ -22,7 +22,7 @@ async function init(ctx: ChildContext) { setCancel = resolve }) - const rpc = createBirpc( + const rpc = createSafeRpc(createBirpc( { onCancel: setCancel, }, @@ -35,9 +35,14 @@ async function init(ctx: ChildContext) { }, on(fn) { process.on('message', fn) }, }, - ) + )) - const environment = await loadEnvironment(ctx.environment.name, ctx.config.root) + const environment = await loadEnvironment(ctx.environment.name, { + root: ctx.config.root, + fetchModule(id) { + return rpc.fetch(id, 'ssr') + }, + }) if (ctx.environment.transformMode) environment.transformMode = ctx.environment.transformMode @@ -52,7 +57,7 @@ async function init(ctx: ChildContext) { environment: 0, prepare: performance.now(), }, - rpc: createSafeRpc(rpc), + rpc, } // @ts-expect-error I know what I am doing :P diff --git a/packages/vitest/src/runtime/vm.ts b/packages/vitest/src/runtime/vm.ts index e9a12e015ba88..323249c164087 100644 --- a/packages/vitest/src/runtime/vm.ts +++ b/packages/vitest/src/runtime/vm.ts @@ -26,7 +26,7 @@ export async function run(ctx: WorkerContext) { setCancel = resolve }) - const rpc = createBirpc( + const rpc = createSafeRpc(createBirpc( { onCancel: setCancel, }, @@ -35,9 +35,14 @@ export async function run(ctx: WorkerContext) { post(v) { port.postMessage(v) }, on(fn) { port.addListener('message', fn) }, }, - ) + )) - const environment = await loadEnvironment(ctx.environment.name, ctx.config.root) + const environment = await loadEnvironment(ctx.environment.name, { + root: ctx.config.root, + fetchModule(id) { + return rpc.fetch(id, 'ssr') + }, + }) if (!environment.setupVM) { const envName = ctx.environment.name @@ -59,7 +64,7 @@ export async function run(ctx: WorkerContext) { environment: performance.now(), prepare: performance.now(), }, - rpc: createSafeRpc(rpc), + rpc, } installSourcemapsSupport({ diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index 7bb1118c6d4cc..d909444561106 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -24,7 +24,7 @@ async function init(ctx: WorkerContext) { setCancel = resolve }) - const rpc = createBirpc( + const rpc = createSafeRpc(createBirpc( { onCancel: setCancel, }, @@ -33,9 +33,14 @@ async function init(ctx: WorkerContext) { post(v) { port.postMessage(v) }, on(fn) { port.addListener('message', fn) }, }, - ) + )) - const environment = await loadEnvironment(ctx.environment.name, ctx.config.root) + const environment = await loadEnvironment(ctx.environment.name, { + root: ctx.config.root, + fetchModule(id) { + return rpc.fetch(id, 'ssr') + }, + }) if (ctx.environment.transformMode) environment.transformMode = ctx.environment.transformMode @@ -50,7 +55,7 @@ async function init(ctx: WorkerContext) { environment: 0, prepare: performance.now(), }, - rpc: createSafeRpc(rpc), + rpc, } // @ts-expect-error I know what I am doing :P diff --git a/test/env-custom/vitest-environment-custom/index.mjs b/test/env-custom/vitest-environment-custom/index.ts similarity index 89% rename from test/env-custom/vitest-environment-custom/index.mjs rename to test/env-custom/vitest-environment-custom/index.ts index da512a72ebda4..e0d82ce17fd76 100644 --- a/test/env-custom/vitest-environment-custom/index.mjs +++ b/test/env-custom/vitest-environment-custom/index.ts @@ -1,6 +1,7 @@ import vm from 'node:vm' +import type { Environment } from 'vitest' -export default { +export default { name: 'custom', transformMode: 'ssr', setupVM({ custom }) { diff --git a/test/env-custom/vitest-environment-custom/package.json b/test/env-custom/vitest-environment-custom/package.json index 634d4cfe70f63..122b09347d049 100644 --- a/test/env-custom/vitest-environment-custom/package.json +++ b/test/env-custom/vitest-environment-custom/package.json @@ -2,6 +2,7 @@ "name": "vitest-environment-custom", "private": true, "exports": { - ".": "./index.mjs" - } + ".": "./index.ts" + }, + "main": "index.ts" }