[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

feat(experimental): add `onModuleRunner` hook to `worker.init` (#9286)

authored by

Vladimir and committed by
GitHub
(Jan 13, 2026, 3:31 PM +0100) e977f3de 2f367fad

+36 -10
+20
packages/vitest/src/runtime/listeners.ts
··· 1 + import type { ModuleRunner } from 'vite/module-runner' 2 + 3 + const cleanupListeners = new Set<() => unknown>() 4 + const moduleRunnerListeners = new Set<(runner: ModuleRunner) => unknown>() 5 + 6 + export function onCleanup(cb: () => unknown): void { 7 + cleanupListeners.add(cb) 8 + } 9 + 10 + export async function cleanup(): Promise<void> { 11 + await Promise.all([...cleanupListeners].map(l => l())) 12 + } 13 + 14 + export function onModuleRunner(cb: (runner: ModuleRunner) => unknown): void { 15 + moduleRunnerListeners.add(cb) 16 + } 17 + 18 + export function emitModuleRunner(moduleRunner: ModuleRunner): void { 19 + moduleRunnerListeners.forEach(l => l(moduleRunner)) 20 + }
+3 -3
packages/vitest/src/runtime/worker.ts
··· 3 3 import type { VitestWorker } from './workers/types' 4 4 import { createStackString, parseStacktrace } from '@vitest/utils/source-map' 5 5 import { setupInspect } from './inspector' 6 + import * as listeners from './listeners' 6 7 import { VitestEvaluatedModules } from './moduleRunner/evaluatedModules' 7 8 import { onCancel, rpcDone } from './rpc' 8 9 9 10 const resolvingModules = new Set<string>() 10 - const globalListeners = new Set<() => unknown>() 11 11 12 12 async function execute(method: 'run' | 'collect', ctx: ContextRPC, worker: VitestWorker, traces: Traces) { 13 13 const prepareStart = performance.now() ··· 40 40 }, 41 41 rpc, 42 42 onCancel, 43 - onCleanup: listener => globalListeners.add(listener), 43 + onCleanup: listeners.onCleanup, 44 44 providedContext: ctx.providedContext, 45 45 onFilterStackTrace(stack) { 46 46 return createStackString(parseStacktrace(stack)) ··· 73 73 } 74 74 75 75 export async function teardown(): Promise<void> { 76 - await Promise.all([...globalListeners].map(l => l())) 76 + await listeners.cleanup() 77 77 } 78 78 79 79 const env = process.env
+3
packages/vitest/src/runtime/workers/base.ts
··· 7 7 import * as spyModule from '@vitest/spy' 8 8 import { setupChaiConfig } from '../../integrations/chai/config' 9 9 import { loadEnvironment } from '../../integrations/env/loader' 10 + import { emitModuleRunner } from '../listeners' 10 11 import { VitestEvaluatedModules } from '../moduleRunner/evaluatedModules' 11 12 import { createNodeImportMeta } from '../moduleRunner/moduleRunner' 12 13 import { startVitestModuleRunner } from '../moduleRunner/startModuleRunner' ··· 115 116 createImportMeta: createNodeImportMeta, 116 117 traces, 117 118 }) 119 + 120 + emitModuleRunner(moduleRunner as any) 118 121 119 122 await run( 120 123 method,
+4
packages/vitest/src/runtime/workers/init.ts
··· 4 4 import type { VitestWorker } from './types' 5 5 import { serializeError } from '@vitest/utils/error' 6 6 import { Traces } from '../../utils/traces' 7 + import * as listeners from '../listeners' 7 8 import { createRuntimeRpc } from '../rpc' 8 9 import * as entrypoint from '../worker' 9 10 ··· 20 21 /** @experimental */ 21 22 export function init(worker: Options): void { 22 23 worker.on(onMessage) 24 + if (worker.onModuleRunner) { 25 + listeners.onModuleRunner(worker.onModuleRunner) 26 + } 23 27 24 28 let runPromise: Promise<unknown> | undefined 25 29 let isRunning = false
+2 -1
packages/vitest/src/runtime/workers/types.ts
··· 1 1 import type { Awaitable } from '@vitest/utils' 2 2 import type { BirpcOptions } from 'birpc' 3 + import type { ModuleRunner } from 'vite/module-runner' 3 4 import type { RuntimeRPC } from '../../types/rpc' 4 5 import type { WorkerGlobalState, WorkerSetupContext } from '../../types/worker' 5 6 import type { Traces } from '../../utils/traces' ··· 12 13 export interface VitestWorker extends WorkerRpcOptions { 13 14 runTests: (state: WorkerGlobalState, traces: Traces) => Awaitable<unknown> 14 15 collectTests: (state: WorkerGlobalState, traces: Traces) => Awaitable<unknown> 15 - 16 + onModuleRunner?: (moduleRunner: ModuleRunner) => Awaitable<unknown> 16 17 setup?: (context: WorkerSetupContext) => Promise<() => Promise<unknown>> 17 18 }
+4 -6
packages/vitest/src/runtime/workers/vm.ts
··· 8 8 import { distDir } from '../../paths' 9 9 import { createCustomConsole } from '../console' 10 10 import { ExternalModulesExecutor } from '../external-executor' 11 + import { emitModuleRunner } from '../listeners' 11 12 import { getDefaultRequestStubs } from '../moduleRunner/moduleEvaluator' 12 13 import { createNodeImportMeta } from '../moduleRunner/moduleRunner' 13 14 import { startVitestModuleRunner, VITEST_VM_CONTEXT_SYMBOL } from '../moduleRunner/startModuleRunner' ··· 98 99 traces, 99 100 }) 100 101 102 + emitModuleRunner(moduleRunner as any) 103 + 101 104 Object.defineProperty(context, VITEST_VM_CONTEXT_SYMBOL, { 102 105 value: { 103 106 context, ··· 124 127 const { run } = (await moduleRunner.import( 125 128 entryFile, 126 129 )) as typeof import('../runVmTests') 127 - const fileSpecs = ctx.files.map(f => 128 - typeof f === 'string' 129 - ? { filepath: f, testLocations: undefined } 130 - : f, 131 - ) 132 130 133 131 try { 134 132 await run( 135 133 method, 136 - fileSpecs, 134 + ctx.files, 137 135 ctx.config, 138 136 moduleRunner, 139 137 traces,