From 26507209f6331823fa8145da689c14bd1a9e3237 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 21 Jan 2026 18:30:51 +0100 Subject: [PATCH 1/5] feat(experimental): option to disable the module runner (#9210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ari Perkkiö --- api/vi.md | 2 + config/experimental.md | 154 +++++++++++++++++++++++++++++++++++++-- guide/mocking/modules.md | 2 + 3 files changed, 151 insertions(+), 7 deletions(-) diff --git a/api/vi.md b/api/vi.md index aa00a279..56e09143 100644 --- a/api/vi.md +++ b/api/vi.md @@ -37,6 +37,8 @@ function mock( Substitutes all imported modules from provided `path` with another module. You can use configured Vite aliases inside a path. The call to `vi.mock` is hoisted, so it doesn't matter where you call it. It will always be executed before all imports. If you need to reference some variables outside of its scope, you can define them inside [`vi.hoisted`](#vi-hoisted) and reference them inside `vi.mock`. +It is recommended to use `vi.mock` or `vi.hoisted` only inside test files. If Vite's [module runner](/config/experimental#experimental-vitemodulerunner) is disabled, they will not be hoisted. This is a performance optimisation to avoid ready unnecessary files. + ::: warning `vi.mock` works only for modules that were imported with the `import` keyword. It doesn't work with `require`. diff --git a/config/experimental.md b/config/experimental.md index 4dc627fd..d79e1625 100644 --- a/config/experimental.md +++ b/config/experimental.md @@ -8,7 +8,7 @@ outline: deep ## experimental.fsModuleCache 4.0.11 {#experimental-fsmodulecache} ::: tip FEEDBACK -Please, leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9221). +Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9221). ::: - **Type:** `boolean` @@ -30,9 +30,9 @@ DEBUG=vitest:cache:fs vitest --experimental.fsModuleCache ### Known Issues -Vitest creates persistent file hash based on file content, its id, vite's environment configuration and coverage status. Vitest tries to use as much information it has about the configuration, but it is still incomplete. At the moment, it is not possible to track your plugin options because there is no standard interface for it. +Vitest creates a persistent file hash based on file content, its id, Vite's environment configuration and coverage status. Vitest tries to use as much information as it has about the configuration, but it is still incomplete. At the moment, it is not possible to track your plugin options because there is no standard interface for it. -If you have a plugin that relies on things outside the file content or the public configuration (like reading another file or a folder), it's possible that the cache will get stale. To workaround that, you can define a [cache key generator](/api/advanced/plugin#definecachekeygenerator) to specify dynamic option or to opt-out of caching for that module: +If you have a plugin that relies on things outside the file content or the public configuration (like reading another file or a folder), it's possible that the cache will get stale. To work around that, you can define a [cache key generator](/api/advanced/plugin#definecachekeygenerator) to specify a dynamic option or to opt out of caching for that module: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' @@ -66,7 +66,7 @@ export default defineConfig({ If you are a plugin author, consider defining a [cache key generator](/api/advanced/plugin#definecachekeygenerator) in your plugin if it can be registered with different options that affect the transform result. -On the other hand, if your plugin should not affect the cache key, you can opt-out by setting `api.vitest.experimental.ignoreFsModuleCache` to `true`: +On the other hand, if your plugin should not affect the cache key, you can opt out by setting `api.vitest.experimental.ignoreFsModuleCache` to `true`: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' @@ -92,7 +92,7 @@ export default defineConfig({ }) ``` -Note that you can still define the cache key generator even the plugin opt-out of module caching. +Note that you can still define the cache key generator even if the plugin opts out of module caching. ## experimental.fsModuleCachePath 4.0.11 {#experimental-fsmodulecachepath} @@ -108,7 +108,7 @@ At the moment, Vitest ignores the [test.cache.dir](/config/cache) or [cacheDir]( ## experimental.openTelemetry 4.0.11 {#experimental-opentelemetry} ::: tip FEEDBACK -Please, leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9222). +Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9222). ::: - **Type:** @@ -179,7 +179,7 @@ It's important that Node can process `sdkPath` content because it is not transfo ## experimental.printImportBreakdown 4.0.15 {#experimental-printimportbreakdown} ::: tip FEEDBACK -Please, leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224). +Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224). ::: - **Type:** `boolean` @@ -197,3 +197,143 @@ 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 4.1.0 {#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/) since 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 (this happens before Vitest knows the `viteModuleRunner` flag) + +::: warning +At the moment, Vitest still requires Vite for certain functionality like the module graph or watch mode. + +Also note that this option only works with `forks` or `threads` [pools](/config/pool). +::: + +### 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. + +### Known Limitations + +Some Vitest features rely on files being transformed. Vitest uses synchronous [Node.js Loaders API](https://nodejs.org/api/module.html#customization-hooks) to transform test files and setup files to support these features: + +- [`import.meta.vitest`](/guide/in-source) +- [`vi.mock`](/api/vi#vi-mock) +- [`vi.hoisted`](/api/vi#vi-hoisted) + +::: warning +This means that Vitest requires at least Node 22.15 for those features to work. At the moment, they also do not work in Deno or Bun. + +Vitest will only detect `vi.mock` and `vi.hoisted` inside of test files, they will not be hoisted inside imported modules. +::: + +This could affect performance because Vitest needs to read the file and process it. If you do not use these features, you can disable the transforms by setting `experimental.nodeLoader` to `false`. Vitest only reads test files and setup files while looking for `vi.mock` or `vi.hoisted`. Using these in other files won't hoist them to the top of the file and can lead to unexpected behavior. + +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, use [customization hooks](https://nodejs.org/api/module.html#customization-hooks) via [`execArgv`](/config/execargv) instead +- no `alias`: aliases are not applied because there is no transformation phase +- `istanbul` coverage provider doesn't work because there is no transformation phase, use `v8` instead + +::: warning Coverage Support +At the momemnt Vitest supports coverage via `v8` provider as long as files can be transformed into JavaScript. To transform TypeScript, Vitest uses [`module.stripTypeScriptTypes`](https://nodejs.org/api/module.html#modulestriptypescripttypescode-options) which is available in Node.js since v22.13. If you are using a custom [module loader](https://nodejs.org/api/module.html#customization-hooks), Vitest is not able to reuse it to transform files for analysis. +::: + +With regards to mocking, it is also important to point out that ES modules do not support property override. This means that code like this won't work anymore: + +```ts +import * as fs from 'node:fs' +import { vi } from 'vitest' + +vi.spyOn(fs, 'readFileSync').mockImplementation(() => '42') // ❌ +``` + +However, Vitest supports auto-spying on modules without overriding their implementation. When `vi.mock` is called with a `spy: true` argument, the module is mocked in a way that preserves original implementations, but all exported functions are wrapped in a `vi.fn()` spy: + +```ts +import * as fs from 'node:fs' +import { vi } from 'vitest' + +vi.mock('node:fs', { spy: true }) + +fs.readFileSync.mockImplementation(() => '42') // ✅ +``` + +Factory mocking is implemented using a top-level await. This means that mocked modules cannot be loaded with `require()` in your source code: + +```ts +vi.mock('node:fs', async (importOriginal) => { + return { + ...await importOriginal(), + readFileSync: vi.fn(), + } +}) + +const fs = require('node:fs') // throws an error +``` + +This limitation exists because factories can be asynchronous. This should not be a problem because Vitest doesn't mock builtin modules inside `node_modules`, which is simillar to how Vitest works by default. + +### TypeScript + +If you are using Node.js 22.18/23.6 or higher, 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 +``` + +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' + +const tsxApi = import.meta.resolve('tsx/esm/api') + +export default defineConfig({ + test: { + execArgv: [ + `--import=data:text/javascript,import * as tsx from "${tsxApi}";tsx.register()`, + ], + experimental: { + viteModuleRunner: false, + }, + }, +}) +``` + +If you are running tests in Deno, TypeScript files are processed by the runtime without any additional configurations. + +## experimental.nodeLoader 4.1.0 {#experimental-nodeloader} + +- **Type:** `boolean` +- **Default:** `true` + +If module runner is disabled, Vitest uses a native [Node.js module loader](https://nodejs.org/api/module.html#customization-hooks) to transform files to support `import.meta.vitest`, `vi.mock` and `vi.hoisted`. + +If you don't use these features, you can disable this to improve performance. diff --git a/guide/mocking/modules.md b/guide/mocking/modules.md index 1ebb2338..171fcde7 100644 --- a/guide/mocking/modules.md +++ b/guide/mocking/modules.md @@ -317,6 +317,8 @@ The module mocking plugins are available in the [`@vitest/mocker` package](https When you run your tests in an emulated environment, Vitest creates a [module runner](https://vite.dev/guide/api-environment-runtimes.html#modulerunner) that can consume Vite code. The module runner is designed in such a way that Vitest can hook into the module evaluation and replace it with the mock, if it was registered. This means that Vitest runs your code in an ESM-like environment, but it doesn't use native ESM mechanism directly. This allows the test runner to bend the rules around ES Modules immutability, allowing users to call `vi.spyOn` on a seemingly ES Module. +If module runner is [disabled](/config/experimental#experimental-vitemodulerunner) and [node loader](/config/experimental#experimental-nodeloader) is not explicitly disabled, Vitest will [register a loader hook](https://nodejs.org/api/module.html#customization-hooks) that transforms original modules into mocked ones. In this mode users cannot call `vi.spyOn` on an ES Module because Vitest uses a native loader mechanism with all its guard rails. In addition to that, Vitest also has to inject a `mock` query into every mocked module which is visible in the stack trace. + ### Browser Mode Vitest uses native ESM in the Browser Mode. This means that we cannot replace the module so easily. Instead, Vitest intercepts the fetch request (via playwright's `page.route` or a Vite plugin API if using `preview` or `webdriverio`) and serves transformed code, if the module was mocked. From 16f589bfb08c25bc583410b9103451a0147f2d83 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Wed, 21 Jan 2026 18:55:32 +0100 Subject: [PATCH 2/5] docs: rephrase viteModuleRunner docs --- config/experimental.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/config/experimental.md b/config/experimental.md index d79e1625..ca977d9c 100644 --- a/config/experimental.md +++ b/config/experimental.md @@ -207,7 +207,7 @@ Controls whether Vitest uses Vite's [module runner](https://vite.dev/guide/api-e 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/) since it doesn't require any additional configuration. +Consider 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 Vite's module runner or in [the browser](/guide/browser/) since it doesn't require any additional configuration. Disabling this flag will disable _all_ file transforms: @@ -226,11 +226,11 @@ Also note that this option only works with `forks` or `threads` [pools](/config/ 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. +Module runner runs all "inlined" 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. +While running JSDOM/happy-dom tests in a permissive fake environment might be justified, running Node.js tests in a non-Node.js environment 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. ### Known Limitations @@ -328,6 +328,7 @@ export default defineConfig({ ``` If you are running tests in Deno, TypeScript files are processed by the runtime without any additional configurations. +::: ## experimental.nodeLoader 4.1.0 {#experimental-nodeloader} From 4f6a98c33c36fc256f60d75449728eacfa38394c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Wed, 21 Jan 2026 19:09:14 +0100 Subject: [PATCH 3/5] docs: fix some wcag-aa color contrast issues (#9468) --- .vitepress/components/ListItem.vue | 16 +++++++++------- .vitepress/theme/styles.css | 11 ++++++++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/.vitepress/components/ListItem.vue b/.vitepress/components/ListItem.vue index 46eaf9d3..28154971 100644 --- a/.vitepress/components/ListItem.vue +++ b/.vitepress/components/ListItem.vue @@ -19,10 +19,10 @@ function reset() { const color = computed(() => { return { '--vp-c-brand-1': state.value === 1 - ? '#66ba1c' + ? 'var(--color-brand)' : state.value === 2 - ? 'rgba(248, 113, 113)' - : 'rgba(250, 204, 21)', + ? 'var(--vp-c-red-1)' + : 'var(--vp-c-yellow-1)', } as any }) @@ -42,7 +42,9 @@ onMounted(async () => {
  • - + + +
    @@ -79,15 +81,15 @@ onMounted(async () => { .icon-spinner { animation: spin 1s linear infinite; - color: rgb(250, 204, 21); + color: var(--vp-c-yellow-1); } .icon-error { - color: rgb(248, 113, 113); + color: var(--vp-c-red-1); } .icon-success { - color: var(--vp-c-brand-1); + color: var(--color-brand); } @keyframes spin { diff --git a/.vitepress/theme/styles.css b/.vitepress/theme/styles.css index 79dfe6bc..fceffc76 100644 --- a/.vitepress/theme/styles.css +++ b/.vitepress/theme/styles.css @@ -5,6 +5,12 @@ /* Vitest */ :root[data-variant="vitest"] { --color-brand: #008039; + /* TODO: home page wcag-aa color contrast (remove this once fixed at void0 theme): + * - why vitest section and texts + * - vitest, resources, versions and social + * - footer + */ + --color-grey: #867e8e; } :root.dark:not([data-theme])[data-variant="vitest"], @@ -12,8 +18,11 @@ --color-brand: var(--color-zest); } +:root[data-variant="vitest"]:not(.dark):not([data-theme="light"]), :root[data-theme="light"][data-variant="vitest"] { --color-brand: #008039; + /* TODO: code block (remove this once fixed at void0 theme) */ + --vp-code-color: #007d38; } @@ -48,4 +57,4 @@ html:not(.dark) .VPContent kbd { padding: 2px 5px; position: relative; top: -1px; -} \ No newline at end of file +} From 4ca84c0b3fdf15b2b5828d0839709ad41fea1c78 Mon Sep 17 00:00:00 2001 From: noise Date: Thu, 22 Jan 2026 20:36:36 +0800 Subject: [PATCH 4/5] docs(cn): dissolve the conflict --- config/experimental.md | 33 +++------------------------------ guide/mocking/modules.md | 13 ++----------- 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/config/experimental.md b/config/experimental.md index 2f44b8cc..ed933fd3 100644 --- a/config/experimental.md +++ b/config/experimental.md @@ -7,13 +7,8 @@ outline: deep ## experimental.fsModuleCache 4.0.11 {#experimental-fsmodulecache} -<<<<<<< HEAD ::: tip 功能反馈 请将关于此功能反馈提交至 [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9221)。 -======= -::: tip FEEDBACK -Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9221). ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c ::: - **类型:** `boolean` @@ -35,15 +30,9 @@ DEBUG=vitest:cache:fs vitest --experimental.fsModuleCache ### 已知问题 {#known-issues} -<<<<<<< HEAD Vitest 基于文件内容、文件 id、vite 的环境配置及覆盖率状态生成持久性文件哈希值。虽然 Vitest 会尽可能利用所有可获取的配置信息,但目前仍存在局限性。由于缺乏标准接口支持,当前无法追踪插件选项的变更情况。 如果你的插件依赖文件内容或公开配置之外的因素(例如读取其他文件或目录),则可能出现缓存失效的情况。要解决这个问题,你可以定义一个 [缓存键生成器](/api/advanced/plugin#definecachekeygenerator) 来指定动态选项,或选择对该模块禁用缓存: -======= -Vitest creates a persistent file hash based on file content, its id, Vite's environment configuration and coverage status. Vitest tries to use as much information as it has about the configuration, but it is still incomplete. At the moment, it is not possible to track your plugin options because there is no standard interface for it. - -If you have a plugin that relies on things outside the file content or the public configuration (like reading another file or a folder), it's possible that the cache will get stale. To work around that, you can define a [cache key generator](/api/advanced/plugin#definecachekeygenerator) to specify a dynamic option or to opt out of caching for that module: ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c ```js [vitest.config.js] import { defineConfig } from 'vitest/config' @@ -76,13 +65,9 @@ export default defineConfig({ ``` 如果你是插件作者,当你的插件可以通过不同配置选项影响转换结果时,建议在插件中定义 [缓存键生成器](/api/advanced/plugin#definecachekeygenerator)。 -<<<<<<< HEAD -另一方面,如果你的插件不应该影响缓存键,你可以通过将 `api.vitest.experimental.ignoreFsModuleCache` 设置为 `true` 来退出缓存机制: -======= If you are a plugin author, consider defining a [cache key generator](/api/advanced/plugin#definecachekeygenerator) in your plugin if it can be registered with different options that affect the transform result. On the other hand, if your plugin should not affect the cache key, you can opt out by setting `api.vitest.experimental.ignoreFsModuleCache` to `true`: ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c ```js [vitest.config.js] import { defineConfig } from 'vitest/config' @@ -108,11 +93,7 @@ export default defineConfig({ }) ``` -<<<<<<< HEAD -请注意,即使插件选择退出模块缓存机制,你仍然可以定义缓存键生成器。 -======= -Note that you can still define the cache key generator even if the plugin opts out of module caching. ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c +请注意,即使插件选择禁用缓存模块,你仍然可以定义缓存键生成器。 ## experimental.fsModuleCachePath 4.0.11 {#experimental-fsmodulecachepath} @@ -127,13 +108,8 @@ Note that you can still define the cache key generator even if the plugin opts o ## experimental.openTelemetry 4.0.11 {#experimental-opentelemetry} -<<<<<<< HEAD ::: tip 功能反馈 请将关于此功能反馈提交至 [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9222)。 -======= -::: tip FEEDBACK -Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9222). ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c ::: - **类型:** @@ -203,13 +179,8 @@ export default defineConfig({ ## experimental.printImportBreakdown 4.0.15 {#experimental-printimportbreakdown} -<<<<<<< HEAD -::: tip 功能反馈 -请将关于此功能反馈提交至 [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224)。 -======= ::: tip FEEDBACK Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224). ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c ::: - **类型:** `boolean` @@ -228,6 +199,8 @@ Please leave feedback regarding this feature in a [GitHub Discussion](https://gi [Vitest UI](/guide/ui#import-breakdown) 会在至少一个文件加载时间超过 500 毫秒时自动显示导入耗时分析。你可手动将此选项设为 `false` 来禁用该功能。 ::: + + ## experimental.viteModuleRunner 4.1.0 {#experimental-vitemodulerunner} - **Type:** `boolean` diff --git a/guide/mocking/modules.md b/guide/mocking/modules.md index 9dfb6d9f..c7f6378d 100644 --- a/guide/mocking/modules.md +++ b/guide/mocking/modules.md @@ -346,18 +346,9 @@ Vitest 所使用的模块模拟插件, ### JSDOM, happy-dom, Node {#jsdom-happy-dom-node} -当你在模拟( emulated )环境中运行测试时, Vitest 会创建一个可执行 Vite 转译代码的 [module runner](https://vite.dev/guide/api-environment-runtimes.html#modulerunner)。 +当你在模拟(emulated)环境中运行测试时,Vitest 会创建一个能够解析 Vite 代码的 [Moudule Runner](https://cn.vite.dev/guide/api-environment-runtimes.html#modulerunner)。该运行器的设计使得 Vitest 可以介入模块评估过程,并在已注册模拟对象时进行替换。这意味着 Vitest 在类 ESM 环境中执行你的代码,但并未直接使用原生 ESM 机制。这种设计允许测试运行器绕过 ES 模块的不可变性限制,使得开发者能够对类 ES 模块的对象调用 `vi.spyOn`。 -<<<<<<< HEAD -这个 module runner 的设计,使得 Vitest 能够在模块执行阶段进行拦截,并在已注册 mock 的情况下用它替换原模块。 -======= -If module runner is [disabled](/config/experimental#experimental-vitemodulerunner) and [node loader](/config/experimental#experimental-nodeloader) is not explicitly disabled, Vitest will [register a loader hook](https://nodejs.org/api/module.html#customization-hooks) that transforms original modules into mocked ones. In this mode users cannot call `vi.spyOn` on an ES Module because Vitest uses a native loader mechanism with all its guard rails. In addition to that, Vitest also has to inject a `mock` query into every mocked module which is visible in the stack trace. - -### Browser Mode ->>>>>>> 4f6a98c33c36fc256f60d75449728eacfa38394c - -换句话说, Vitest 会在一个“ 类 ESM ”环境中运行测试代码,但并不直接依赖原生 ESM 机制。 -这使得测试运行器能够打破 ES Modules 的不可变性规则,让你可以在看似 ES Module 的模块上调用 `vi.spyOn`。 +如果 [Moudule Runner](/config/experimental#experimental-vitemodulerunner) 被禁用且未显式禁用 [Node loader](/config/experimental#experimental-nodeloader),Vitest 将 [注册加载器钩子](https://nodejs.org/api/module.html#customization-hooks) 将原始模块转换为模拟模块。在此模式下,用户无法对 ES 模块调用 `vi.spyOn`,因为 Vitest 使用了带有所有保护机制的原生加载器方案。此外,Vitest 还必须在每个模拟模块中注入可见于调用堆栈的 `mock` 查询参数。 ### 浏览器模式 {#browser-mode} From f2c1a0a28261859015ef99141e37a3457a0bfccb Mon Sep 17 00:00:00 2001 From: noise Date: Thu, 22 Jan 2026 20:45:14 +0800 Subject: [PATCH 5/5] docs(cn): update api/vi.md --- api/vi.md | 2 +- config/experimental.md | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/api/vi.md b/api/vi.md index 13c30eba..54e1e77c 100644 --- a/api/vi.md +++ b/api/vi.md @@ -34,7 +34,7 @@ function mock( 用另一个模块替换提供的 `path` 中的所有导入模块。我们可以在路径内使用配置的 Vite 别名。对 `vi.mock` 的调用是悬挂式的,因此在何处调用并不重要。它总是在所有导入之前执行。如果需要在其作用域之外引用某些变量,可以在 [`vi.hoisted`](/api/vi#vi-hoisted)中定义它们,并在 `vi.mock` 中引用它们。 -It is recommended to use `vi.mock` or `vi.hoisted` only inside test files. If Vite's [module runner](/config/experimental#experimental-vitemodulerunner) is disabled, they will not be hoisted. This is a performance optimisation to avoid ready unnecessary files. +建议仅在测试文件中使用 `vi.mock` 或 `vi.hoisted`。若禁用 Vite 的 [module runner](/config/experimental#experimental-vitemodulerunner),这些模拟声明将不会被提升。此设计作为性能优化手段,可避免预加载不必要的文件。 ::: warning `vi.mock` 仅对使用 `import` 关键字导入的模块有效。它对 `require` 无效。 diff --git a/config/experimental.md b/config/experimental.md index ed933fd3..3fe6319e 100644 --- a/config/experimental.md +++ b/config/experimental.md @@ -65,9 +65,7 @@ export default defineConfig({ ``` 如果你是插件作者,当你的插件可以通过不同配置选项影响转换结果时,建议在插件中定义 [缓存键生成器](/api/advanced/plugin#definecachekeygenerator)。 -If you are a plugin author, consider defining a [cache key generator](/api/advanced/plugin#definecachekeygenerator) in your plugin if it can be registered with different options that affect the transform result. - -On the other hand, if your plugin should not affect the cache key, you can opt out by setting `api.vitest.experimental.ignoreFsModuleCache` to `true`: +另一方面,如果你的插件不应该影响缓存键,你可以通过将 `api.vitest.experimental.ignoreFsModuleCache` 设置为 `true` 来退出缓存机制: ```js [vitest.config.js] import { defineConfig } from 'vitest/config' @@ -179,8 +177,8 @@ export default defineConfig({ ## experimental.printImportBreakdown 4.0.15 {#experimental-printimportbreakdown} -::: tip FEEDBACK -Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224). +::: tip 功能反馈 +请将关于此功能反馈提交至 [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9224)。 ::: - **类型:** `boolean`