Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
2943ccf
feat(experimental): allow disabling the module runner
sheremet-va Dec 8, 2025
085be59
fix: throw an error in vmForks/vmThreads
sheremet-va Dec 8, 2025
c25402a
feat: implement nativeModuleRunner
sheremet-va Dec 8, 2025
318eb6b
chore: cleanup types
sheremet-va Dec 8, 2025
0611b57
fix: watcher respects non-client/ssr environments
sheremet-va Dec 8, 2025
3e4caa2
feat: support watch mode
sheremet-va Dec 8, 2025
4e5464b
fix: support module.register
sheremet-va Dec 8, 2025
3c40971
feat: support import.meta.vitest
sheremet-va Dec 8, 2025
c047490
chore: cli-config
sheremet-va Dec 8, 2025
b83f29c
chore: add sample project
sheremet-va Dec 9, 2025
3fd5618
chore: cleanup
sheremet-va Dec 9, 2025
e4b0d2e
chore: cleanup
sheremet-va Dec 9, 2025
fe86182
feat: support automock, autospy and redirect mock types
sheremet-va Dec 9, 2025
3f7e2b3
fix: show module as external in UI
sheremet-va Dec 9, 2025
2273518
fix: run setup file for every test, execute in-source tests as separa…
sheremet-va Dec 9, 2025
6c44609
feat: first implementation of factory mocking
sheremet-va Dec 10, 2025
4091d0d
chore: collect
sheremet-va Dec 12, 2025
0926f28
chore: refactor native module mocker
sheremet-va Dec 12, 2025
f76caa0
refactor: cleanup exports collection
sheremet-va Dec 12, 2025
d6f72bd
fix: support importActual and recursive factory
sheremet-va Dec 12, 2025
086c47c
fix: support vi.importMock
sheremet-va Dec 12, 2025
06a351e
fix: support mocking deps
sheremet-va Dec 12, 2025
8b4f29b
fix(mocker): support top level import if dependency is not circular
sheremet-va Dec 15, 2025
f50aa81
fix: allow `export *` when automocking
sheremet-va Dec 15, 2025
a4e603e
test: add more tests
sheremet-va Dec 15, 2025
d458c67
fix: update loading errors
sheremet-va Dec 15, 2025
34f1bb3
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Dec 15, 2025
d3db1bf
chore: cleanup
sheremet-va Dec 15, 2025
b653ee3
chore: cleanup
sheremet-va Dec 15, 2025
0ab2dab
fix: override is false by default
sheremet-va Dec 16, 2025
69ca0d8
chore: cleanup
sheremet-va Dec 16, 2025
4786dd1
refactor: move the example to test/
sheremet-va Dec 16, 2025
5bb68aa
docs: cleanup
sheremet-va Dec 16, 2025
74a84c4
chore: add try/catch
sheremet-va Dec 17, 2025
c81d363
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Dec 17, 2025
f7def15
fix: listen for unhandled errors in vm pool
sheremet-va Dec 17, 2025
3f96c63
fix(windows): support circular manual mock
sheremet-va Dec 17, 2025
f8ab6a5
chore: replace #test-loader with #nodejs-worker-loader
sheremet-va Dec 18, 2025
34350d6
chore: remove a warning hint
sheremet-va Dec 18, 2025
fda5d88
docs: mention it works only in forks/threads
sheremet-va Dec 18, 2025
fa80150
chore: nitpicks
sheremet-va Dec 18, 2025
f8c558d
test: add imports from basic.ts
sheremet-va Dec 18, 2025
3ded894
fix: move mock=actual resolution to worker loader
sheremet-va Dec 18, 2025
d99af1d
fix: load custom env with a regular import
sheremet-va Dec 18, 2025
f0c1ae2
chore: lint
sheremet-va Dec 18, 2025
861e0d1
fix: wrong default
sheremet-va Dec 18, 2025
a5dc591
fix: load automocked builtins properly
sheremet-va Dec 18, 2025
c48303e
chore: support import on windows
sheremet-va Dec 18, 2025
a097b32
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Dec 19, 2025
d21b3a8
chore: use `process.setSourceMapsEnabled` if available
sheremet-va Dec 22, 2025
694f9e9
chore: document limitation of mocking builtins
sheremet-va Dec 22, 2025
3c5f534
chore: don't mock anything inside node_modules for now
sheremet-va Dec 22, 2025
bf901f3
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Dec 27, 2025
9bb9ef7
chore: add a comment
sheremet-va Dec 27, 2025
f1f1d72
chore: review
sheremet-va Jan 12, 2026
d47477e
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Jan 12, 2026
892e8e2
chore: cleanup
sheremet-va Jan 12, 2026
ea60b20
fix: check before ?
sheremet-va Jan 12, 2026
afe7ef9
chore: lockfile
sheremet-va Jan 12, 2026
485f627
chore: add `describe`
sheremet-va Jan 12, 2026
fa5674e
chore: cleanup
sheremet-va Jan 12, 2026
01d64d0
chore: cleanup
sheremet-va Jan 12, 2026
7206421
test: add a cts test
sheremet-va Jan 12, 2026
2df65e4
chore: cleanup
sheremet-va Jan 12, 2026
cca67da
refactor: use a util to run no-module-runner tests
sheremet-va Jan 12, 2026
b84b160
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Jan 13, 2026
2dc04b9
chore: cleanup
sheremet-va Jan 13, 2026
8586581
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Jan 14, 2026
75f7d04
test: move native tests
sheremet-va Jan 14, 2026
f4a8bb4
chore: fix v8 support
sheremet-va Jan 14, 2026
630c595
chore: cleanup
sheremet-va Jan 14, 2026
5dc2d19
chore: use local-pkg instead
sheremet-va Jan 14, 2026
2f6680d
test: add v8 coverage test
sheremet-va Jan 14, 2026
af5f13a
chore: add comment
sheremet-va Jan 14, 2026
4a65754
test: add watch and snapshot tests
sheremet-va Jan 14, 2026
1dcf484
fix: respect transform mode
sheremet-va Jan 14, 2026
229d3d7
chore: lint
sheremet-va Jan 14, 2026
89b324b
test: remove only
sheremet-va Jan 14, 2026
3dd5e62
chore: pass down url
sheremet-va Jan 14, 2026
d2fcd47
chore: convert to path
sheremet-va Jan 14, 2026
79064fc
chore: cleanup
sheremet-va Jan 15, 2026
be09438
chore: cleanup
sheremet-va Jan 15, 2026
e9512ae
chore: fix query params
sheremet-va Jan 15, 2026
cb4a7ed
test: make coverage test more stable
sheremet-va Jan 15, 2026
2dc9546
chore: oops
sheremet-va Jan 15, 2026
2cf4de4
docs: add notes
sheremet-va Jan 15, 2026
8155942
test(coverage): native runner with v8
AriPerkkio Jan 19, 2026
41d181e
fix: proper `startOffset` when `import.meta.vitest` without module ru…
AriPerkkio Jan 19, 2026
045179e
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Jan 19, 2026
f27507b
Merge branch 'main' of github.com:vitest-dev/vitest into 12-08-feat_e…
sheremet-va Jan 21, 2026
04ae041
test(coverage): exclude node 20 tests if registerHooks is not available
sheremet-va Jan 21, 2026
8b10b8a
fix: use IMPORT_META_TEST() function instead of appending IMPORT_META…
sheremet-va Jan 21, 2026
85ba069
test: don't process node_modules
sheremet-va Jan 21, 2026
74d009a
chore: include vitest/cjs-lib in deps optimisation
sheremet-va Jan 21, 2026
5d9db1a
test: remove try/catch
sheremet-va Jan 21, 2026
33750a0
test: pass down skip
sheremet-va Jan 21, 2026
6c663fd
refactor(coverage): what is this madness
sheremet-va Jan 21, 2026
6c6d6ba
chore: cleanup
sheremet-va Jan 21, 2026
cf69ac8
test: be conservative with what is included
sheremet-va Jan 21, 2026
a6fa2ab
test: fix dynamic test import
sheremet-va Jan 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions docs/config/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,98 @@ Note that if the file path is too long, Vitest will truncate it at the start unt
::: info
[Vitest UI](/guide/ui#import-breakdown) shows a breakdown of imports automatically if at least one file took longer than 500 milliseconds to load. You can manually set this option to `false` to disable this.
:::

## experimental.viteModuleRunner <Version type="experimental">4.0.16</Version> {#experimental-vitemodulerunner}

- **Type:** `boolean`
- **Default:** `true`

Controls whether Vitest uses Vite's [module runner](https://vite.dev/guide/api-environment-runtimes#modulerunner) to run the code or fallback to the native `import`.

If this option is defined in the root config, all [projects](/guide/projects) will inherit it automatically.

We recommend disabling the module runner if you are running tests in the same environment as your code (server backend or simple scripts, for example). However, we still recommend running `jsdom`/`happy-dom` tests with the module runner or in [the browser](/guide/browser/) as it doesn't require any additional configuration.

Disabling this flag will disable _all_ file transforms:

- test files and your source code are not processed by Vite
- your global setup files are not processed
- your custom runner/pool/environment files are not processed
- your config file is still processed by Vite's config resolution mechanism (this happens before Vitest knows the flag)

::: warning
At the moment, Vitest still requires Vite for certain functionality like the module graph or watch mode.
:::

### Module Runner

By default, Vitest runs tests in a very permissive module runner sandbox powered by Vite's [Environment API](https://vite.dev/guide/api-environment.html#environment-api). Every file is categorized as either an "inline" module or an "external" module.

Module runner runs all "inline" modules. It provides `import.meta.env`, `require`, `__dirname`, `__filename`, static `import`, and has its own module resolution mechanism. This makes it very easy to run code when you don't want to configure the environment and just need to test that the bare JavaScript logic you wrote works as intended.

All "external" modules run in native mode, meaning they are executed outside of the module runner sandbox. If you are running tests in Node.js, these files are imported with the native `import` keyword and processed by Node.js directly.

While running JSDOM/happy-dom tests in a permissive fake environment might be justified, running Node.js tests in a non-Node.js environment is counter-productive as it can hide and silence potential errors you may encounter in production, especially if your code doesn't require any additional transformations provided by Vite plugins.

### Limitations

Some Vitest features rely on files being transformed. Vitest uses [Node.js Loaders API](https://nodejs.org/api/module.html#customization-hooks) to transform certain files to support these features:

- [`import.meta.vitest`](/guide/in-source)
- partial [`vi.mock`](/api/vi#vi-mock) support

This could affect performance because Vitest needs to read the file and process it. If you do not use these features, you can disable them by setting `experimental.nodeLoader` to `false`.

Some features will not work due to the nature of `viteModuleRunner`, including:

- no `import.meta.env`: `import.meta.env` is a Vite feature, use `process.env` instead
- no `plugins`: plugins are not applied because there is no transformation phase
- no `alias`: aliases are not applied because there is no transformation phase

### TypeScript

If you are using Node.js 22.18/23.6 or higher, then TypeScript will be [transformed natively](https://nodejs.org/en/learn/typescript/run-natively) by Node.js.

::: warning TypeScript with Node.js 22.6-22.18
If you are using Node.js version between 22.6 and 22.18, you can also enable native TypeScript support via `--experimental-strip-types` flag:

```shell
NODE_OPTIONS="--experimental-strip-types" vitest
```

Note that Node.js will print an experimental warning for every test file; you can silence the warning by providing `--no-warnings` flag:

```shell
NODE_OPTIONS="--experimental-strip-types --no-warnings" vitest
```
Comment thread
sheremet-va marked this conversation as resolved.
Outdated
:::

If you are using TypeScript and Node.js version lower than 22.6, then you will need to either:

- build your test files and source code and run those files directly
- import a [custom loader](https://nodejs.org/api/module.html#customization-hooks) via `execArgv` flag

```ts
import { defineConfig } from 'vitest/config'

export default defineConfig({
test: {
// TODO: validate
execArgv: ['--require=tsx/esm'],
experimental: {
viteModuleRunner: false,
},
},
})
```

If you are running tests in Deno, TypeScript files are processed by the runtime without any additional configurations.

## experimental.nodeLoader <Version type="experimental">4.0.16</Version> {#experimental-nodeloader}

- **Type:** `boolean`
- **Default:** `true`

If module runner is disabled, Vitest uses a module loader to transform files to support `import.meta.vitest` and `vi.mock`.

If you don't use these features, you can disable this.
3 changes: 2 additions & 1 deletion packages/vitest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"#module-evaluator": {
"types": "./dist/module-evaluator.d.ts",
"default": "./dist/module-evaluator.js"
}
},
"#test-loader": "./dist/nodejs-worker-loader.js"
Comment thread
sheremet-va marked this conversation as resolved.
Outdated
},
"exports": {
".": {
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const entries = {
'worker': 'src/public/worker.ts',
'module-runner': 'src/public/module-runner.ts',
'module-evaluator': 'src/runtime/moduleRunner/moduleEvaluator.ts',
'nodejs-worker-loader.js': 'src/runtime/nodejsWorkerLoader.ts',

// for performance reasons we bundle them separately so we don't import everything at once
// 'worker': 'src/runtime/worker.ts',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { SnapshotEnvironment } from '@vitest/snapshot/environment'
import type { SerializedConfig } from '../../../runtime/config'
import type { VitestModuleRunner } from '../../../runtime/moduleRunner/moduleRunner'
import type { TestModuleRunner } from '../../../runtime/moduleRunner/testModuleRunner'

export async function resolveSnapshotEnvironment(
config: SerializedConfig,
executor: VitestModuleRunner,
moduleRunner: TestModuleRunner,
): Promise<SnapshotEnvironment> {
if (!config.snapshotEnvironment) {
const { VitestNodeSnapshotEnvironment } = await import('./node')
return new VitestNodeSnapshotEnvironment()
}

const mod = await executor.import(config.snapshotEnvironment)
const mod = await moduleRunner.import(config.snapshotEnvironment)
if (typeof mod.default !== 'object' || !mod.default) {
throw new Error(
'Snapshot environment module must have a default export object with a shape of `SnapshotEnvironment`',
Expand Down
3 changes: 3 additions & 0 deletions packages/vitest/src/node/cli/cli-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@
experimental: {
description: 'Experimental features.',
argument: '<features>',
subcommands: {

Check failure on line 772 in packages/vitest/src/node/cli/cli-config.ts

View workflow job for this annotation

GitHub Actions / Lint: node-latest, ubuntu-latest

Property 'nodeLoader' is missing in type '{ fsModuleCache: { description: string; }; fsModuleCachePath: null; openTelemetry: null; printImportBreakdown: { description: string; }; viteModuleRunner: { description: string; }; }' but required in type 'CLIOptions<{ fsModuleCache?: boolean | undefined; fsModuleCachePath?: string | undefined; openTelemetry?: { enabled: boolean; sdkPath?: string | undefined; } | undefined; printImportBreakdown?: boolean | undefined; viteModuleRunner?: boolean | undefined; nodeLoader?: boolean | undefined; }>'.
fsModuleCache: {
description: 'Enable caching of modules on the file system between reruns.',
},
Expand All @@ -778,6 +778,9 @@
printImportBreakdown: {
description: 'Print import breakdown after the summary. If the reporter doesn\'t support summary, this will have no effect. Note that UI\'s "Module Graph" tab always has an import breakdown.',
},
viteModuleRunner: {
description: 'Control whether Vitest uses Vite\'s module runner to run the code or fallback to the native `import`. (default: `true`)',
},
},
},
// disable CLI options
Expand Down
2 changes: 2 additions & 0 deletions packages/vitest/src/node/config/serializeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ export function serializeConfig(project: TestProject): SerializedConfig {
experimental: {
fsModuleCache: config.experimental.fsModuleCache ?? false,
printImportBreakdown: config.experimental.printImportBreakdown,
viteModuleRunner: config.experimental.viteModuleRunner ?? true,
nodeLoader: config.experimental.nodeLoader ?? true,
},
}
}
13 changes: 8 additions & 5 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { version } from '../../package.json' with { type: 'json' }
import { WebSocketReporter } from '../api/setup'
import { distDir } from '../paths'
import { wildcardPatternToRegExp } from '../utils/base'
import { NativeModuleRunner } from '../utils/nativeModuleRunner'
import { convertTasksToEvents } from '../utils/tasks'
import { Traces } from '../utils/traces'
import { astCollectTests, createFailedFileTask } from './ast-collect'
Expand Down Expand Up @@ -238,11 +239,13 @@ export class Vitest {
this._tmpDir,
)
const environment = server.environments.__vitest__
this.runner = new ServerModuleRunner(
environment,
this._fetcher,
resolved,
)
this.runner = resolved.experimental.viteModuleRunner === false
? new NativeModuleRunner(resolved.root)
: new ServerModuleRunner(
environment,
this._fetcher,
resolved,
)

if (this.config.watch) {
// hijack server restart
Expand Down
14 changes: 10 additions & 4 deletions packages/vitest/src/node/plugins/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,21 @@ export function WorkspaceVitestPlugin(
name: { label: name, color },
}

vitestConfig.experimental ??= {}

// always inherit the global `fsModuleCache` value even without `extends: true`
if (testConfig.experimental?.fsModuleCache == null && project.vitest.config.experimental?.fsModuleCache !== null) {
vitestConfig.experimental ??= {}
if (testConfig.experimental?.fsModuleCache == null && project.vitest.config.experimental?.fsModuleCache != null) {
vitestConfig.experimental.fsModuleCache = project.vitest.config.experimental.fsModuleCache
}
if (testConfig.experimental?.fsModuleCachePath == null && project.vitest.config.experimental?.fsModuleCachePath !== null) {
vitestConfig.experimental ??= {}
if (testConfig.experimental?.fsModuleCachePath == null && project.vitest.config.experimental?.fsModuleCachePath != null) {
vitestConfig.experimental.fsModuleCachePath = project.vitest.config.experimental.fsModuleCachePath
}
if (testConfig.experimental?.viteModuleRunner == null && project.vitest.config.experimental?.viteModuleRunner != null) {
vitestConfig.experimental.viteModuleRunner = project.vitest.config.experimental.viteModuleRunner
}
if (testConfig.experimental?.nodeLoader == null && project.vitest.config.experimental?.nodeLoader != null) {
vitestConfig.experimental.nodeLoader = project.vitest.config.experimental.nodeLoader
}

return {
base: '/',
Expand Down
31 changes: 31 additions & 0 deletions packages/vitest/src/node/pools/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,36 @@ export function createMethodsRPC(project: TestProject, methodsOptions: MethodsOp
getCountOfFailedTests() {
return vitest.state.getCountOfFailedTests()
},

ensureModuleGraphEntry(id, importer) {
const filepath = id.startsWith('file:') ? fileURLToPath(id) : id
const importerPath = importer.startsWith('file:') ? fileURLToPath(importer) : importer
// environment itself doesn't matter
const moduleGraph = project.vite.environments.__vitest__?.moduleGraph
if (!moduleGraph) {
// TODO: is it possible?
console.error('no module graph for', id)
return
}
const importerNode = moduleGraph.getModuleById(importerPath) || moduleGraph.createFileOnlyEntry(importerPath)
const moduleNode = moduleGraph.getModuleById(filepath) || moduleGraph.createFileOnlyEntry(filepath)

if (!moduleGraph.idToModuleMap.has(importerPath)) {
importerNode.id = importerPath
moduleGraph.idToModuleMap.set(importerPath, importerNode)
}
if (!moduleGraph.idToModuleMap.has(filepath)) {
moduleNode.id = filepath
moduleGraph.idToModuleMap.set(filepath, moduleNode)
}

// this is checked by the "printError" function - TODO: is there a better way?
moduleNode.transformResult = {
code: ' ',
map: null,
}
importerNode.importedModules.add(moduleNode)
moduleNode.importers.add(importerNode)
},
}
}
23 changes: 17 additions & 6 deletions packages/vitest/src/node/project.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { GlobOptions } from 'tinyglobby'
import type { ViteDevServer, InlineConfig as ViteInlineConfig } from 'vite'
import type { DevEnvironment, ViteDevServer, InlineConfig as ViteInlineConfig } from 'vite'
import type { ModuleRunner } from 'vite/module-runner'
import type { Typechecker } from '../typecheck/typechecker'
import type { ProvidedContext } from '../types/general'
Expand All @@ -24,6 +24,7 @@ import pm from 'picomatch'
import { glob } from 'tinyglobby'
import { setup } from '../api/setup'
import { createDefinesScript } from '../utils/config-helpers'
import { NativeModuleRunner } from '../utils/nativeModuleRunner'
import { isBrowserEnabled, resolveConfig } from './config/resolveConfig'
import { serializeConfig } from './config/serializeConfig'
import { createFetchModuleFunction } from './environments/fetchModule'
Expand Down Expand Up @@ -568,11 +569,21 @@ export class TestProject {
)

const environment = server.environments.__vitest__
this.runner = new ServerModuleRunner(
environment,
this._fetcher,
this._config,
)
this.runner = this._config.experimental.viteModuleRunner === false
? new NativeModuleRunner(this._config.root)
: new ServerModuleRunner(
environment,
this._fetcher,
this._config,
)
}

/** @internal */
public _getViteEnvironments(): DevEnvironment[] {
return [
...Object.values(this.browser?.vite.environments || {}),
...Object.values(this.vite.environments || {}),
]
}

private _serializeOverriddenConfig(): SerializedConfig {
Expand Down
15 changes: 15 additions & 0 deletions packages/vitest/src/node/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,21 @@ export interface InlineConfig {
* Enabling this will also show a breakdown by default in UI, but you can always press a button to toggle it.
*/
printImportBreakdown?: boolean

/**
* Controls whether Vitest uses Vite's module runner to run the code or fallback to the native `import`.
*
* If Node.js cannot process the code, consider registering [module loader](https://nodejs.org/api/module.html#customization-hooks) via `execArgv`.
* @default true
*/
viteModuleRunner?: boolean
/**
* If module runner is disabled, Vitest uses a module loader to transform files to support
* `import.meta.vitest` and `vi.mock`.
*
* If you don't use these features, you can disable this.
*/
nodeLoader?: boolean
Comment thread
sheremet-va marked this conversation as resolved.
}
}

Expand Down
34 changes: 18 additions & 16 deletions packages/vitest/src/node/watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ export class VitestWatcher {
}

const projects = this.vitest.projects.filter((project) => {
const moduleGraph = project.browser?.vite.moduleGraph || project.vite.moduleGraph
return moduleGraph.getModulesByFile(filepath)?.size
return project._getViteEnvironments().some(({ moduleGraph }) => {
return moduleGraph.getModulesByFile(filepath)?.size
})
})
if (!projects.length) {
// if there are no modules it's possible that server was restarted
Expand All @@ -195,9 +196,8 @@ export class VitestWatcher {
const files: string[] = []

for (const project of projects) {
const mods = project.browser?.vite.moduleGraph.getModulesByFile(filepath)
|| project.vite.moduleGraph.getModulesByFile(filepath)
if (!mods || !mods.size) {
const environmentMods = project._getViteEnvironments().map(({ moduleGraph }) => moduleGraph.getModulesByFile(filepath))
if (!environmentMods.length) {
continue
}

Expand All @@ -211,17 +211,19 @@ export class VitestWatcher {
}

let rerun = false
for (const mod of mods) {
mod.importers.forEach((i) => {
if (!i.file) {
return
}

const needsRerun = this.handleFileChanged(i.file)
if (needsRerun) {
rerun = true
}
})
for (const mods of environmentMods) {
for (const mod of mods || []) {
mod.importers.forEach((i) => {
if (!i.file) {
return
}

const needsRerun = this.handleFileChanged(i.file)
if (needsRerun) {
rerun = true
}
})
}
}

if (rerun) {
Expand Down
3 changes: 2 additions & 1 deletion packages/vitest/src/public/module-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export {
type ContextModuleRunnerOptions,
startVitestModuleRunner,
VITEST_VM_CONTEXT_SYMBOL,
} from '../runtime/moduleRunner/startModuleRunner'
} from '../runtime/moduleRunner/startVitestModuleRunner'
export type { TestModuleRunner } from '../runtime/moduleRunner/testModuleRunner'
export { getWorkerState } from '../runtime/utils'
2 changes: 1 addition & 1 deletion packages/vitest/src/public/worker.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { runBaseTests, setupEnvironment } from '../runtime/workers/base'
export { runBaseTests, setupBaseEnvironment as setupEnvironment } from '../runtime/workers/base'
export { init } from '../runtime/workers/init'
2 changes: 2 additions & 0 deletions packages/vitest/src/runtime/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ export interface SerializedConfig {
experimental: {
fsModuleCache: boolean
printImportBreakdown: boolean | undefined
viteModuleRunner: boolean
nodeLoader: boolean
}
}

Expand Down
Loading
Loading