Skip to content

Commit 9be01ba

Browse files
feat!: use module-runner instead of vite-node (#8208)
Co-authored-by: Ari Perkkiö <[email protected]>
1 parent 94ab392 commit 9be01ba

File tree

145 files changed

+3187
-1678
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+3187
-1678
lines changed

.npmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ strict-peer-dependencies=false
33
provenance=true
44
shell-emulator=true
55
registry=https://registry.npmjs.org/
6-
VITE_NODE_DEPS_MODULE_DIRECTORIES=/node_modules/,/packages/
6+
VITEST_MODULE_DIRECTORIES=/node_modules/,/packages/

docs/advanced/runner.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,14 @@ export default CustomRunner
121121
```
122122

123123
::: warning
124-
Vitest also injects an instance of `ViteNodeRunner` as `__vitest_executor` property. You can use it to process files in `importFile` method (this is default behavior of `TestRunner` and `BenchmarkRunner`).
124+
Vitest also injects an instance of `ModuleRunner` from `vite/module-runner` as `moduleRunner` property. You can use it to process files in `importFile` method (this is default behavior of `TestRunner` and `BenchmarkRunner`).
125125

126-
`ViteNodeRunner` exposes `executeId` method, which is used to import test files in a Vite-friendly environment. Meaning, it will resolve imports and transform file content at runtime so that Node can understand it:
126+
`ModuleRunner` exposes `import` method, which is used to import test files in a Vite-friendly environment. Meaning, it will resolve imports and transform file content at runtime so that Node can understand it:
127127

128128
```ts
129129
export default class Runner {
130130
async importFile(filepath: string) {
131-
await this.__vitest_executor.executeId(filepath)
131+
await this.moduleRunner.import(filepath)
132132
}
133133
}
134134
```

docs/config/index.md

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ Handling for dependencies resolution.
233233

234234
#### deps.optimizer {#deps-optimizer}
235235

236-
- **Type:** `{ ssr?, web? }`
236+
- **Type:** `{ ssr?, client? }`
237237
- **See also:** [Dep Optimization Options](https://vitejs.dev/config/dep-optimization-options.html)
238238

239239
Enable dependency optimization. If you have a lot of tests, this might improve their performance.
@@ -245,7 +245,7 @@ When Vitest encounters the external library listed in `include`, it will be bund
245245
- Your `alias` configuration is now respected inside bundled packages
246246
- Code in your tests is running closer to how it's running in the browser
247247

248-
Be aware that only packages in `deps.optimizer?.[mode].include` option are bundled (some plugins populate this automatically, like Svelte). You can read more about available options in [Vite](https://vitejs.dev/config/dep-optimization-options.html) docs (Vitest doesn't support `disable` and `noDiscovery` options). By default, Vitest uses `optimizer.web` for `jsdom` and `happy-dom` environments, and `optimizer.ssr` for `node` and `edge` environments, but it is configurable by [`transformMode`](#testtransformmode).
248+
Be aware that only packages in `deps.optimizer?.[mode].include` option are bundled (some plugins populate this automatically, like Svelte). You can read more about available options in [Vite](https://vitejs.dev/config/dep-optimization-options.html) docs (Vitest doesn't support `disable` and `noDiscovery` options). By default, Vitest uses `optimizer.client` for `jsdom` and `happy-dom` environments, and `optimizer.ssr` for `node` and `edge` environments.
249249

250250
This options also inherits your `optimizeDeps` configuration (for web Vitest will extend `optimizeDeps`, for ssr - `ssr.optimizeDeps`). If you redefine `include`/`exclude` option in `deps.optimizer` it will extend your `optimizeDeps` when running tests. Vitest automatically removes the same options from `include`, if they are listed in `exclude`.
251251

@@ -260,15 +260,15 @@ You will not be able to edit your `node_modules` code for debugging, since the c
260260

261261
Enable dependency optimization.
262262

263-
#### deps.web {#deps-web}
263+
#### deps.client {#deps-client}
264264

265265
- **Type:** `{ transformAssets?, ... }`
266266

267-
Options that are applied to external files when transform mode is set to `web`. By default, `jsdom` and `happy-dom` use `web` mode, while `node` and `edge` environments use `ssr` transform mode, so these options will have no affect on files inside those environments.
267+
Options that are applied to external files when the environment is set to `client`. By default, `jsdom` and `happy-dom` use `client` environment, while `node` and `edge` environments use `ssr`, so these options will have no affect on files inside those environments.
268268

269269
Usually, files inside `node_modules` are externalized, but these options also affect files in [`server.deps.external`](#server-deps-external).
270270

271-
#### deps.web.transformAssets
271+
#### deps.client.transformAssets
272272

273273
- **Type:** `boolean`
274274
- **Default:** `true`
@@ -281,7 +281,7 @@ This module will have a default export equal to the path to the asset, if no que
281281
At the moment, this option only works with [`vmThreads`](#vmthreads) and [`vmForks`](#vmforks) pools.
282282
:::
283283

284-
#### deps.web.transformCss
284+
#### deps.client.transformCss
285285

286286
- **Type:** `boolean`
287287
- **Default:** `true`
@@ -294,7 +294,7 @@ If CSS files are disabled with [`css`](#css) options, this option will just sile
294294
At the moment, this option only works with [`vmThreads`](#vmthreads) and [`vmForks`](#vmforks) pools.
295295
:::
296296

297-
#### deps.web.transformGlobPattern
297+
#### deps.client.transformGlobPattern
298298

299299
- **Type:** `RegExp | RegExp[]`
300300
- **Default:** `[]`
@@ -560,7 +560,7 @@ import type { Environment } from 'vitest'
560560

561561
export default <Environment>{
562562
name: 'custom',
563-
transformMode: 'ssr',
563+
viteEnvironment: 'ssr',
564564
setup() {
565565
// custom setup
566566
return {
@@ -1676,28 +1676,6 @@ Will call [`vi.unstubAllEnvs`](/api/vi#vi-unstuballenvs) before each test.
16761676

16771677
Will call [`vi.unstubAllGlobals`](/api/vi#vi-unstuballglobals) before each test.
16781678

1679-
### testTransformMode {#testtransformmode}
1680-
1681-
- **Type:** `{ web?, ssr? }`
1682-
1683-
Determine the transform method for all modules imported inside a test that matches the glob pattern. By default, relies on the environment. For example, tests with JSDOM environment will process all files with `ssr: false` flag and tests with Node environment process all modules with `ssr: true`.
1684-
1685-
#### testTransformMode.ssr
1686-
1687-
- **Type:** `string[]`
1688-
- **Default:** `[]`
1689-
1690-
Use SSR transform pipeline for all modules inside specified tests.<br>
1691-
Vite plugins will receive `ssr: true` flag when processing those files.
1692-
1693-
#### testTransformMode&#46;web
1694-
1695-
- **Type:** `string[]`
1696-
- **Default:** `[]`
1697-
1698-
First do a normal transform pipeline (targeting browser), then do a SSR rewrite to run the code in Node.<br>
1699-
Vite plugins will receive `ssr: false` flag when processing those files.
1700-
17011679
### snapshotFormat<NonProjectOption />
17021680

17031681
- **Type:** `PrettyFormatOptions`

docs/guide/environment.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import type { Environment } from 'vitest/environments'
4848

4949
export default <Environment>{
5050
name: 'custom',
51-
transformMode: 'ssr',
51+
viteEnvironment: 'ssr',
5252
// optional - only if you support "experimental-vm" pool
5353
async setupVM() {
5454
const vm = await import('node:vm')
@@ -74,7 +74,7 @@ export default <Environment>{
7474
```
7575

7676
::: warning
77-
Vitest requires `transformMode` option on environment object. It should be equal to `ssr` or `web`. This value determines how plugins will transform source code. If it's set to `ssr`, plugin hooks will receive `ssr: true` when transforming or resolving files. Otherwise, `ssr` is set to `false`.
77+
Vitest requires `viteEnvironment` option on environment object (fallbacks to the Vitest environment name by default). It should be equal to `ssr`, `client` or any custom [Vite environment](https://vite.dev/guide/api-environment) name. This value determines which environment is used to process file.
7878
:::
7979

8080
You also have access to default Vitest environments through `vitest/environments` entry:

docs/guide/migration.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,31 @@ $ pnpm run test:dev math.test.ts
145145
```
146146
:::
147147

148+
### Replacing `vite-node` with [Module Runner](https://vite.dev/guide/api-environment-runtimes.html#modulerunner)
149+
150+
Module Runner is a successor to `vite-node` implemented directly in Vite. Vitest now uses it directly instead of having a wrapper around Vite SSR handler. This means that certain features are no longer available:
151+
152+
- `VITE_NODE_DEPS_MODULE_DIRECTORIES` environment variable was replaced with `VITEST_MODULE_DIRECTORIES`
153+
- Vitest no longer injects `__vitest_executor` into every [test runner](/advanced/runner). Instead, it injects `moduleRunner` which is an instance of [`ModuleRunner`](https://vite.dev/guide/api-environment-runtimes.html#modulerunner)
154+
- `vitest/execute` entry point was removed. It was always meant to be internal
155+
- [Custom environments](/guide/environment) no longer need to provide a `transformMode` property. Instead, provide `viteEnvironment`. If it is not provided, Vitest will use the environment name to transform files on the server (see [`server.environments`](https://vite.dev/guide/api-environment-instances.html))
156+
- `vite-node` is no longer a dependency of Vitest
157+
- `deps.optimizer.web` was renamed to [`deps.optimizer.client`](/config/#deps-optimizer-client). You can also use any custom names to apply optimizer configs when using other server environments
158+
159+
Vite has its own externalization mechanism, but we decided to keep using the old one to reduce the amount of breaking changes. You can keep using [`server.deps`](/config/#server-deps) to inline or externalize packages.
160+
161+
This update should not be noticeable unless you rely on advanced features mentioned above.
162+
148163
### Deprecated APIs are Removed
149164

150165
Vitest 4.0 removes some deprecated APIs, including:
151166

152167
- `poolMatchGlobs` config option. Use [`projects`](/guide/projects) instead.
153168
- `environmentMatchGlobs` config option. Use [`projects`](/guide/projects) instead.
154169
- `workspace` config option. Use [`projects`](/guide/projects) instead.
170+
- `deps.external`, `deps.inline`, `deps.fallbackCJS` config options. Use `server.deps.external`, `server.deps.inline`, or `server.deps.fallbackCJS` instead.
155171

156-
This release also removes all deprecated types. This finally fixes an issue where Vitest accidentally pulled in `node` types (see [#5481](https://github.com/vitest-dev/vitest/issues/5481) and [#6141](https://github.com/vitest-dev/vitest/issues/6141)).
172+
This release also removes all deprecated types. This finally fixes an issue where Vitest accidentally pulled in `@types/node` (see [#5481](https://github.com/vitest-dev/vitest/issues/5481) and [#6141](https://github.com/vitest-dev/vitest/issues/6141)).
157173

158174
## Migrating from Jest {#jest}
159175

packages/browser/src/client/tester/runner.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from 'vitest/internal/browser'
1313
import { NodeBenchmarkRunner, VitestTestRunner } from 'vitest/runners'
1414
import { createStackString, parseStacktrace } from '../../../../utils/src/source-map'
15-
import { executor, getWorkerState } from '../utils'
15+
import { getWorkerState, moduleRunner } from '../utils'
1616
import { rpc } from './rpc'
1717
import { VitestBrowserSnapshotEnvironment } from './snapshot'
1818

@@ -117,7 +117,7 @@ export function createBrowserRunner(
117117
await rpc().onAfterSuiteRun({
118118
coverage,
119119
testFiles: files.map(file => file.name),
120-
transformMode: 'browser',
120+
environment: '__browser__',
121121
projectName: this.config.name,
122122
})
123123
}
@@ -223,7 +223,7 @@ export async function initiateRunner(
223223

224224
const BrowserRunner = createBrowserRunner(runnerClass, mocker, state, {
225225
takeCoverage: () =>
226-
takeCoverageInsideWorker(config.coverage, executor),
226+
takeCoverageInsideWorker(config.coverage, moduleRunner),
227227
})
228228
if (!config.snapshotOptions.snapshotEnvironment) {
229229
config.snapshotOptions.snapshotEnvironment = new VitestBrowserSnapshotEnvironment()
@@ -238,8 +238,8 @@ export async function initiateRunner(
238238
})
239239

240240
const [diffOptions] = await Promise.all([
241-
loadDiffConfig(config, executor as any),
242-
loadSnapshotSerializers(config, executor as any),
241+
loadDiffConfig(config, moduleRunner as any),
242+
loadSnapshotSerializers(config, moduleRunner as any),
243243
])
244244
runner.config.diffOptions = diffOptions
245245
getWorkerState().onFilterStackTrace = (stack: string) => {

packages/browser/src/client/tester/state.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,16 @@ const state: WorkerGlobalState = {
2525
config,
2626
environment: {
2727
name: 'browser',
28-
transformMode: 'web',
28+
viteEnvironment: 'client',
2929
setup() {
3030
throw new Error('Not called in the browser')
3131
},
3232
},
3333
onCleanup: fn => getBrowserState().cleanups.push(fn),
34-
moduleCache: getBrowserState().moduleCache,
34+
evaluatedModules: getBrowserState().evaluatedModules,
35+
resolvingModules: getBrowserState().resolvingModules,
3536
moduleExecutionInfo: new Map(),
37+
metaEnv: null as any,
3638
rpc: null as any,
3739
durations: {
3840
environment: 0,

packages/browser/src/client/tester/tester.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
startTests,
1111
stopCoverageInsideWorker,
1212
} from 'vitest/internal/browser'
13-
import { executor, getBrowserState, getConfig, getWorkerState } from '../utils'
13+
import { getBrowserState, getConfig, getWorkerState, moduleRunner } from '../utils'
1414
import { setupDialogsSpy } from './dialog'
1515
import { setupConsoleLogSpy } from './logger'
1616
import { VitestBrowserClientMocker } from './mocker'
@@ -101,6 +101,7 @@ async function prepareTestEnvironment(options: PrepareOptions) {
101101

102102
const state = getWorkerState()
103103

104+
state.metaEnv = import.meta.env
104105
state.onCancel = onCancel
105106
state.rpc = rpc as any
106107

@@ -207,7 +208,7 @@ async function prepare(options: PrepareOptions) {
207208

208209
await Promise.all([
209210
setupCommonEnv(config),
210-
startCoverageInsideWorker(config.coverage, executor, { isolate: config.browser.isolate }),
211+
startCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.browser.isolate }),
211212
(async () => {
212213
const VitestIndex = await import('vitest')
213214
Object.defineProperty(window, '__vitest_index__', {
@@ -249,7 +250,7 @@ async function cleanup() {
249250
.catch(error => unhandledError(error, 'Cleanup Error'))
250251
}
251252
state.environmentTeardownRun = true
252-
await stopCoverageInsideWorker(config.coverage, executor, { isolate: config.browser.isolate }).catch((error) => {
253+
await stopCoverageInsideWorker(config.coverage, moduleRunner, { isolate: config.browser.isolate }).catch((error) => {
253254
return unhandledError(error, 'Coverage Error')
254255
})
255256
}

packages/browser/src/client/utils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { VitestRunner } from '@vitest/runner'
2-
import type { SerializedConfig, WorkerGlobalState } from 'vitest'
2+
import type { EvaluatedModules, SerializedConfig, WorkerGlobalState } from 'vitest'
33
import type { IframeOrchestrator } from './orchestrator'
44
import type { CommandsManager } from './tester/utils'
55

@@ -13,10 +13,10 @@ export async function importFs(id: string): Promise<any> {
1313
return getBrowserState().wrapModule(() => import(/* @vite-ignore */ name))
1414
}
1515

16-
export const executor = {
16+
export const moduleRunner = {
1717
isBrowser: true,
1818

19-
executeId: (id: string): Promise<any> => {
19+
import: (id: string): Promise<any> => {
2020
if (id[0] === '/' || id[1] === ':') {
2121
return importFs(id)
2222
}
@@ -65,7 +65,8 @@ export function ensureAwaited<T>(promise: (error?: Error) => Promise<T>): Promis
6565
export interface BrowserRunnerState {
6666
files: string[]
6767
runningFiles: string[]
68-
moduleCache: Map<string, any>
68+
resolvingModules: Set<string>
69+
evaluatedModules: EvaluatedModules
6970
config: SerializedConfig
7071
provider: string
7172
runner: VitestRunner

packages/browser/src/node/rpc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject, defaultMocke
122122

123123
function setupClient(project: TestProject, rpcId: string, ws: WebSocket) {
124124
const mockResolver = new ServerMockResolver(globalServer.vite, {
125-
moduleDirectories: project.config.server?.deps?.moduleDirectories,
125+
moduleDirectories: project.config?.deps?.moduleDirectories,
126126
})
127127
const mocker = project.browser?.provider.mocker
128128

0 commit comments

Comments
 (0)