Skip to content

Commit 78ed73a

Browse files
authored
feat: promote fsModuleCache to a top-level option (#10734)
1 parent 22d353a commit 78ed73a

28 files changed

Lines changed: 315 additions & 241 deletions

File tree

docs/.vitepress/config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,14 @@ export default ({ mode }: { mode: string }) => {
470470
text: 'cache',
471471
link: '/config/cache',
472472
},
473+
{
474+
text: 'fsModuleCache',
475+
link: '/config/fsmodulecache',
476+
},
477+
{
478+
text: 'fsModuleCachePath',
479+
link: '/config/fsmodulecachepath',
480+
},
473481
{
474482
text: 'sequence',
475483
link: '/config/sequence',

docs/api/advanced/plugin.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ The project's `configFile` can be accessed in Vite's config: `project.vite.confi
124124
Note that this will also inherit the `name` - Vitest doesn't allow multiple projects with the same name, so this will throw an error. Make sure you specified a different name. You can access the current name via the `project.name` property and all used names are available in the `vitest.projects` array.
125125
:::
126126

127-
### experimental_defineCacheKeyGenerator <Version type="experimental">4.0.11</Version> <Experimental /> {#definecachekeygenerator}
127+
### defineCacheKeyGenerator <Version>5.0.0</Version> {#definecachekeygenerator}
128128

129129
```ts
130130
interface CacheKeyIdGeneratorContext {
@@ -133,7 +133,7 @@ interface CacheKeyIdGeneratorContext {
133133
sourceCode: string
134134
}
135135
136-
function experimental_defineCacheKeyGenerator(
136+
function defineCacheKeyGenerator(
137137
callback: (context: CacheKeyIdGeneratorContext) => string | undefined | null | false
138138
): void
139139
```
@@ -142,7 +142,7 @@ Define a generator that will be applied before hashing the cache key.
142142

143143
Use this to make sure Vitest generates correct hash. It is a good idea to define this function if your plugin can be registered with different options.
144144

145-
This is called only if [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache) is defined.
145+
This is called only if [`fsModuleCache`](/config/fsmodulecache) is enabled.
146146

147147
```ts
148148
interface PluginOptions {
@@ -159,8 +159,8 @@ export function plugin(options: PluginOptions) {
159159
options.replacePropertyValue
160160
)
161161
},
162-
configureVitest({ experimental_defineCacheKeyGenerator }) {
163-
experimental_defineCacheKeyGenerator(() => {
162+
configureVitest({ defineCacheKeyGenerator }) {
163+
defineCacheKeyGenerator(() => {
164164
// since these options affect the transform result,
165165
// return them together as a unique string
166166
return options.replacePropertyKey + options.replacePropertyValue

docs/api/advanced/vitest.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ This method will [collect tests](#parsespecification) from an array of specifica
603603
function experimental_clearCache(): Promise<void>
604604
```
605605

606-
Deletes all Vitest caches, including [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache).
606+
Deletes all Vitest caches, including [`fsModuleCache`](/config/fsmodulecache).
607607

608608
## experimental_getSourceModuleDiagnostic <Version type="experimental">4.0.15</Version> <Experimental /> {#getsourcemodulediagnostic}
609609

docs/config/experimental.md

Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5,106 +5,6 @@ outline: deep
55

66
# experimental
77

8-
## experimental.fsModuleCache <Version type="experimental">4.0.11</Version> {#experimental-fsmodulecache}
9-
10-
::: tip FEEDBACK
11-
Please leave feedback regarding this feature in a [GitHub Discussion](https://github.com/vitest-dev/vitest/discussions/9221).
12-
:::
13-
14-
- **Type:** `boolean`
15-
- **Default:** `false`
16-
17-
Enabling this option allows Vitest to keep cached modules on the file system, making tests run faster between reruns.
18-
19-
You can delete the old cache by running [`vitest --clearCache`](/guide/cli#clearcache).
20-
21-
::: warning BROWSER SUPPORT
22-
At the moment, this option does not affect [the browser](/guide/browser/).
23-
:::
24-
25-
You can debug if your modules are cached by running vitest with a `DEBUG=vitest:cache:fs` environment variable:
26-
27-
```shell
28-
DEBUG=vitest:cache:fs vitest --experimental.fsModuleCache
29-
```
30-
31-
### Known Issues
32-
33-
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.
34-
35-
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:
36-
37-
```js [vitest.config.js]
38-
import { defineConfig } from 'vitest/config'
39-
40-
export default defineConfig({
41-
plugins: [
42-
{
43-
name: 'vitest-cache',
44-
configureVitest({ experimental_defineCacheKeyGenerator }) {
45-
experimental_defineCacheKeyGenerator(({ id, sourceCode }) => {
46-
// never cache this id
47-
if (id.includes('do-not-cache')) {
48-
return false
49-
}
50-
51-
// cache this file based on the value of a dynamic variable
52-
if (sourceCode.includes('myDynamicVar')) {
53-
return process.env.DYNAMIC_VAR_VALUE
54-
}
55-
})
56-
}
57-
}
58-
],
59-
test: {
60-
experimental: {
61-
fsModuleCache: true,
62-
},
63-
},
64-
})
65-
```
66-
67-
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.
68-
69-
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`:
70-
71-
```js [vitest.config.js]
72-
import { defineConfig } from 'vitest/config'
73-
74-
export default defineConfig({
75-
plugins: [
76-
{
77-
name: 'vitest-cache',
78-
api: {
79-
vitest: {
80-
experimental: {
81-
ignoreFsModuleCache: true,
82-
},
83-
},
84-
},
85-
},
86-
],
87-
test: {
88-
experimental: {
89-
fsModuleCache: true,
90-
},
91-
},
92-
})
93-
```
94-
95-
Note that you can still define the cache key generator even if the plugin opts out of module caching.
96-
97-
## experimental.fsModuleCachePath <Version type="experimental">4.0.11</Version> {#experimental-fsmodulecachepath}
98-
99-
- **Type:** `string`
100-
- **Default:** `'node_modules/.experimental-vitest-cache'`
101-
102-
Directory where the file system cache is located.
103-
104-
By default, Vitest will try to find the workspace root and store the cache inside the `node_modules` folder. The root is based on your package manager's lockfile (for example, `.package-lock.json`, `.yarn-state.yml`, `.pnpm/lock.yaml` and so on).
105-
106-
At the moment, Vitest ignores the [test.cache.dir](/config/cache) or [cacheDir](https://vite.dev/config/shared-options#cachedir) options completely and creates a separate folder.
107-
1088
## experimental.openTelemetry <Version type="experimental">4.0.11</Version> {#experimental-opentelemetry}
1099

11010
::: tip FEEDBACK

docs/config/fsmodulecache.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
title: fsModuleCache | Config
3+
outline: deep
4+
---
5+
6+
# fsModuleCache <Version>5.0.0</Version>
7+
8+
- **Type:** `boolean`
9+
- **Default:** `false`
10+
- **CLI:** `--fsModuleCache`, `--fsModuleCache=false`
11+
12+
In watch mode, Vitest caches all transformed files in memory, which makes reruns fast. However, this cache is discarded once the test run finishes. Enabling this option allows Vitest to persist the transformed modules on the file system, so they can be reused across reruns and separate Vitest processes.
13+
14+
A single cache directory is shared by every project in the workspace. By default it lives in `node_modules` at the workspace root (so it is naturally invalidated when dependencies are reinstalled); use [`fsModuleCachePath`](/config/fsmodulecachepath) to change its location. You can delete the cache by running [`vitest --clearCache`](/guide/cli#clearcache).
15+
16+
::: warning BROWSER SUPPORT
17+
At the moment, this option does not affect [the browser](/guide/browser/).
18+
:::
19+
20+
You can debug if your modules are cached by running vitest with a `DEBUG=vitest:cache:fs` environment variable:
21+
22+
```shell
23+
DEBUG=vitest:cache:fs vitest --fsModuleCache
24+
```
25+
26+
::: tip
27+
The location of the cache is a single, workspace-wide directory. See [`fsModuleCachePath`](/config/fsmodulecachepath) to move it.
28+
:::
29+
30+
## Known Issues
31+
32+
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.
33+
34+
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:
35+
36+
```js [vitest.config.js]
37+
import { defineConfig } from 'vitest/config'
38+
39+
export default defineConfig({
40+
plugins: [
41+
{
42+
name: 'vitest-cache',
43+
configureVitest({ defineCacheKeyGenerator }) {
44+
defineCacheKeyGenerator(({ id, sourceCode }) => {
45+
// never cache this id
46+
if (id.includes('do-not-cache')) {
47+
return false
48+
}
49+
50+
// cache this file based on the value of a dynamic variable
51+
if (sourceCode.includes('myDynamicVar')) {
52+
return process.env.DYNAMIC_VAR_VALUE
53+
}
54+
})
55+
}
56+
}
57+
],
58+
test: {
59+
fsModuleCache: true,
60+
},
61+
})
62+
```
63+
64+
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.
65+
66+
On the other hand, if your plugin should not affect the cache key, you can opt out by setting `api.vitest.ignoreFsModuleCache` to `true`:
67+
68+
```js [vitest.config.js]
69+
import { defineConfig } from 'vitest/config'
70+
71+
export default defineConfig({
72+
plugins: [
73+
{
74+
name: 'vitest-cache',
75+
api: {
76+
vitest: {
77+
ignoreFsModuleCache: true,
78+
},
79+
},
80+
},
81+
],
82+
test: {
83+
fsModuleCache: true,
84+
},
85+
})
86+
```
87+
88+
Note that you can still define the cache key generator even if the plugin opts out of module caching.

docs/config/fsmodulecachepath.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
title: fsModuleCachePath | Config
3+
outline: deep
4+
---
5+
6+
# fsModuleCachePath <Version>5.0.0</Version>
7+
8+
- **Type:** `string`
9+
- **Default:** `'node_modules/.vitest-cache'` (resolved from the workspace root)
10+
- **CLI:** `--fsModuleCachePath=<path>`
11+
12+
Directory where the [`fsModuleCache`](/config/fsmodulecache) is stored.
13+
14+
This can be set per project; projects that don't override it fall back to the root's cache directory. The lockfile metadata used to invalidate the cache is always shared across the whole workspace.
15+
16+
By default Vitest stores the cache inside `node_modules` at the workspace root. The root is based on your package manager's lockfile (for example, `.package-lock.json`, `.yarn-state.yml`, `.pnpm/lock.yaml` and so on). Keeping it inside `node_modules` means the cache is naturally invalidated whenever dependencies are reinstalled.
17+
18+
```ts
19+
import { defineConfig } from 'vitest/config'
20+
21+
export default defineConfig({
22+
test: {
23+
fsModuleCache: true,
24+
fsModuleCachePath: 'node_modules/.vitest-cache',
25+
},
26+
})
27+
```

docs/guide/cli-generated.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,20 @@ Default timeout of a teardown function in milliseconds (default: `10000`)
819819

820820
Maximum number of concurrent tests and suites during test file execution (default: `5`)
821821

822+
### fsModuleCache
823+
824+
- **CLI:** `--fsModuleCache`
825+
- **Config:** [fsModuleCache](/config/fsmodulecache)
826+
827+
Cache transformed modules on the file system and reuse them between reruns (default: `false`)
828+
829+
### fsModuleCachePath
830+
831+
- **CLI:** `--fsModuleCachePath <path>`
832+
- **Config:** [fsModuleCachePath](/config/fsmodulecachepath)
833+
834+
Directory where the `fsModuleCache` is stored (default: `node_modules/.vitest-cache`)
835+
822836
### expect.requireAssertions
823837

824838
- **CLI:** `--expect.requireAssertions`
@@ -901,7 +915,7 @@ List all available tags instead of running tests. `--list-tags=json` will output
901915

902916
- **CLI:** `--clearCache`
903917

904-
Delete all Vitest caches, including `experimental.fsModuleCache`, without running any tests. This will reduce the performance in the subsequent test run.
918+
Delete all Vitest caches, including the `fsModuleCache`, without running any tests. This will reduce the performance in the subsequent test run.
905919

906920
### tagsFilter
907921

@@ -916,13 +930,6 @@ Run only tests with the specified tags. You can use logical operators `&&` (and)
916930

917931
Should Vitest throw an error if test has a tag that is not defined in the config. (default: `true`)
918932

919-
### experimental.fsModuleCache
920-
921-
- **CLI:** `--experimental.fsModuleCache`
922-
- **Config:** [experimental.fsModuleCache](/config/experimental#experimental-fsmodulecache)
923-
924-
Enable caching of modules on the file system between reruns.
925-
926933
### experimental.importDurations.print
927934

928935
- **CLI:** `--experimental.importDurations.print <boolean|on-warn>`

docs/guide/improving-performance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ You can limit the working directory when Vitest searches for files using [`test.
7979

8080
## Caching Between Reruns
8181

82-
In watch mode, Vitest caches all transformed files in memory, which makes reruns fast. However, this cache is discarded once the test run finishes. By enabling [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache), Vitest persists this cache to the file system so it can be reused across reruns.
82+
In watch mode, Vitest caches all transformed files in memory, which makes reruns fast. However, this cache is discarded once the test run finishes. By enabling [`fsModuleCache`](/config/fsmodulecache), Vitest persists this cache to the file system so it can be reused across reruns.
8383

8484
This improvement is most noticeable when rerunning a small number of tests that depend on a large module graph. For full test suites, parallelization already mitigates the cost because other tests populate the in-memory cache while earlier tests are still running. For example, running one test file with a huge module graph (>900 modules):
8585

docs/guide/ui.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ By left-clicking on the module node, you open the Module Info view.
118118
<img alt="The module info view for an inlined module" img-light src="/ui/light-module-info.png">
119119
<img alt="The module info view for an inlined module" img-dark src="/ui/dark-module-info.png">
120120

121-
This view is separated into two parts. The top part shows the full module ID and some diagnostics about the module. If [`experimental.fsModuleCache`](/config/experimental#experimental-fsmodulecache) is enabled, there will be a "cached" or "not cached" badge. On the right you can see time diagnostics:
121+
This view is separated into two parts. The top part shows the full module ID and some diagnostics about the module. If [`fsModuleCache`](/config/fsmodulecache) is enabled, there will be a "cached" or "not cached" badge. On the right you can see time diagnostics:
122122

123123
- Self Time: the time it took to import the module, excluding static imports.
124124
- Total Time: the time it took to import the module, including static imports. Note that this does not include `transform` time of the current module.

packages/ui/client/components/ModuleTransformResultView.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const ext = computed(() => props.id?.split(/\./g).pop() || 'js')
4545
4646
const source = computed(() => result.value?.source?.trim() || '')
4747
const isCached = computed(() => {
48-
if (!result.value || !('code' in result.value) || !config.value.experimental?.fsModuleCache) {
48+
if (!result.value || !('code' in result.value) || !config.value.fsModuleCache) {
4949
return undefined
5050
}
5151
const index = result.value.code.lastIndexOf('vitestCache=')
@@ -239,7 +239,7 @@ onKeyStroke('Escape', () => {
239239
cached
240240
</Badge>
241241
<template #popper>
242-
This module is cached on the file system under `experimental.fsModuleCachePath` ("node_modules/.exprtimental-vitest-cache" by default).
242+
This module is cached on the file system under `fsModuleCachePath` ("node_modules/.vitest-cache" by default).
243243
</template>
244244
</VueTooltip>
245245
<VueTooltip v-if="isCached === false" class="inline" cursor-help>

0 commit comments

Comments
 (0)
Sponsor
SponsoredKunjungi sekarang
Promo