Skip to content

Commit ef1464f

Browse files
hi-ogawasheremet-va
andauthoredJan 23, 2025··
fix: apply development|production condition on Vite 6 (#7301)
Co-authored-by: Vladimir Sheremet <sleuths.slews0s@icloud.com>
1 parent 0b404e5 commit ef1464f

File tree

18 files changed

+233
-25
lines changed

18 files changed

+233
-25
lines changed
 

‎docs/guide/migration.md

+4
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ expect(() => {
129129

130130
See PR for more details: [#5876](https://github.com/vitest-dev/vitest/pull/5876).
131131

132+
### `module` condition export is not resolved by default on Vite 6
133+
134+
Vite 6 allows more flexible [`resolve.conditions`](https://vite.dev/config/shared-options#resolve-conditions) options and Vitest configures it to exclude `module` conditional export by default.
135+
132136
### `Custom` Type is Deprecated <Badge type="danger">API</Badge> {#custom-type-is-deprecated}
133137

134138
The `Custom` type is now an alias for the `Test` type. Note that Vitest updated the public types in 2.1 and changed exported names to `RunnerCustomCase` and `RunnerTestCase`:

‎packages/vitest/src/node/plugins/index.ts

+5-10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { VitestOptimizer } from './optimizer'
2020
import { SsrReplacerPlugin } from './ssrReplacer'
2121
import {
2222
deleteDefineConfig,
23+
getDefaultResolveOptions,
2324
hijackVitePluginInject,
2425
resolveFsAllow,
2526
} from './utils'
@@ -73,6 +74,8 @@ export async function VitestPlugin(
7374
open = testConfig.uiBase ?? '/__vitest__/'
7475
}
7576

77+
const resolveOptions = getDefaultResolveOptions()
78+
7679
const config: ViteConfig = {
7780
root: viteConfig.test?.root || options.root,
7881
esbuild:
@@ -86,11 +89,8 @@ export async function VitestPlugin(
8689
legalComments: 'inline',
8790
},
8891
resolve: {
89-
// by default Vite resolves `module` field, which not always a native ESM module
90-
// setting this option can bypass that and fallback to cjs version
91-
mainFields: [],
92+
...resolveOptions,
9293
alias: testConfig.alias,
93-
conditions: ['node'],
9494
},
9595
server: {
9696
...testConfig.api,
@@ -115,12 +115,7 @@ export async function VitestPlugin(
115115
// @ts-ignore Vite 6 compat
116116
environments: {
117117
ssr: {
118-
resolve: {
119-
// by default Vite resolves `module` field, which not always a native ESM module
120-
// setting this option can bypass that and fallback to cjs version
121-
mainFields: [],
122-
conditions: ['node'],
123-
},
118+
resolve: resolveOptions,
124119
},
125120
},
126121
test: {

‎packages/vitest/src/node/plugins/utils.ts

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
import type { DepsOptimizationOptions, InlineConfig } from '../types/config'
77
import { dirname } from 'pathe'
88
import { searchForWorkspaceRoot, version as viteVersion } from 'vite'
9+
import * as vite from 'vite'
910
import { rootDir } from '../../paths'
1011
import { VitestCache } from '../cache'
1112

@@ -147,3 +148,23 @@ export function resolveFsAllow(
147148
rootDir,
148149
]
149150
}
151+
152+
export function getDefaultResolveOptions(): vite.ResolveOptions {
153+
return {
154+
// by default Vite resolves `module` field, which is not always a native ESM module
155+
// setting this option can bypass that and fallback to cjs version
156+
mainFields: [],
157+
// same for `module` condition and Vite 5 doesn't even allow excluding it,
158+
// but now it's possible since Vite 6.
159+
conditions: getDefaultServerConditions(),
160+
}
161+
}
162+
163+
function getDefaultServerConditions(): string[] {
164+
const viteMajor = Number(viteVersion.split('.')[0])
165+
if (viteMajor >= 6) {
166+
const conditions: string[] = (vite as any).defaultServerConditions
167+
return conditions.filter(c => c !== 'module')
168+
}
169+
return ['node']
170+
}

‎packages/vitest/src/node/plugins/workspace.ts

+4-10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { VitestOptimizer } from './optimizer'
1616
import { SsrReplacerPlugin } from './ssrReplacer'
1717
import {
1818
deleteDefineConfig,
19+
getDefaultResolveOptions,
1920
hijackVitePluginInject,
2021
resolveFsAllow,
2122
} from './utils'
@@ -92,14 +93,12 @@ export function WorkspaceVitestPlugin(
9293
}
9394
}
9495

96+
const resolveOptions = getDefaultResolveOptions()
9597
const config: ViteConfig = {
9698
root,
9799
resolve: {
98-
// by default Vite resolves `module` field, which not always a native ESM module
99-
// setting this option can bypass that and fallback to cjs version
100-
mainFields: [],
100+
...resolveOptions,
101101
alias: testConfig.alias,
102-
conditions: ['node'],
103102
},
104103
esbuild: viteConfig.esbuild === false
105104
? false
@@ -130,12 +129,7 @@ export function WorkspaceVitestPlugin(
130129
// @ts-ignore Vite 6 compat
131130
environments: {
132131
ssr: {
133-
resolve: {
134-
// by default Vite resolves `module` field, which not always a native ESM module
135-
// setting this option can bypass that and fallback to cjs version
136-
mainFields: [],
137-
conditions: ['node'],
138-
},
132+
resolve: resolveOptions,
139133
},
140134
},
141135
test: {

‎packages/vitest/src/node/pool.ts

+15-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { TestSpecification } from './spec'
55
import type { BuiltinPool, Pool } from './types/pool-options'
66
import { isatty } from 'node:tty'
77
import mm from 'micromatch'
8+
import { version as viteVersion } from 'vite'
89
import { isWindows } from '../utils/env'
910
import { createForksPool } from './pools/forks'
1011
import { createThreadsPool } from './pools/threads'
@@ -91,11 +92,14 @@ export function createPool(ctx: Vitest): ProcessPool {
9192

9293
// in addition to resolve.conditions Vite also adds production/development,
9394
// see: https://github.com/vitejs/vite/blob/af2aa09575229462635b7cbb6d248ca853057ba2/packages/vite/src/node/plugins/resolve.ts#L1056-L1080
94-
const potentialConditions = new Set([
95-
'production',
96-
'development',
97-
...ctx.vite.config.resolve.conditions,
98-
])
95+
const viteMajor = Number(viteVersion.split('.')[0])
96+
const potentialConditions = new Set(viteMajor >= 6
97+
? (ctx.vite.config.ssr.resolve?.conditions ?? [])
98+
: [
99+
'production',
100+
'development',
101+
...ctx.vite.config.resolve.conditions,
102+
])
99103
const conditions = [...potentialConditions]
100104
.filter((condition) => {
101105
if (condition === 'production') {
@@ -106,6 +110,12 @@ export function createPool(ctx: Vitest): ProcessPool {
106110
}
107111
return true
108112
})
113+
.map((condition) => {
114+
if (viteMajor >= 6 && condition === 'development|production') {
115+
return ctx.vite.config.isProduction ? 'production' : 'development'
116+
}
117+
return condition
118+
})
109119
.flatMap(c => ['--conditions', c])
110120

111121
// Instead of passing whole process.execArgv to the workers, pick allowed options.

‎pnpm-lock.yaml

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "@vitest/test-dep-conditions-indirect",
3+
"type": "module",
4+
"private": true,
5+
"exports": {
6+
"./custom": {
7+
"custom": "./true.js",
8+
"default": "./false.js"
9+
},
10+
"./module": {
11+
"module": "./true.js",
12+
"default": "./false.js"
13+
},
14+
"./node": {
15+
"node": "./true.js",
16+
"default": "./false.js"
17+
},
18+
"./development": {
19+
"development": "./true.js",
20+
"default": "./false.js"
21+
},
22+
"./production": {
23+
"production": "./true.js",
24+
"default": "./false.js"
25+
}
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import conditionCustom from '@vitest/test-dep-conditions-indirect/custom'
2+
import conditionDevelopment from '@vitest/test-dep-conditions-indirect/development'
3+
import conditionModule from '@vitest/test-dep-conditions-indirect/module'
4+
import conditionNode from '@vitest/test-dep-conditions-indirect/node'
5+
import conditionProductioin from '@vitest/test-dep-conditions-indirect/production'
6+
7+
export default {
8+
conditionCustom,
9+
conditionModule,
10+
conditionNode,
11+
conditionDevelopment,
12+
conditionProductioin,
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default !!import.meta.__IS_INLINE__
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "@vitest/test-dep-conditions",
3+
"type": "module",
4+
"private": true,
5+
"exports": {
6+
"./custom": {
7+
"custom": "./true.js",
8+
"default": "./false.js"
9+
},
10+
"./module": {
11+
"module": "./true.js",
12+
"default": "./false.js"
13+
},
14+
"./node": {
15+
"node": "./true.js",
16+
"default": "./false.js"
17+
},
18+
"./development": {
19+
"development": "./true.js",
20+
"default": "./false.js"
21+
},
22+
"./production": {
23+
"production": "./true.js",
24+
"default": "./false.js"
25+
},
26+
"./inline": "./inline.js",
27+
"./indirect": "./indirect.js"
28+
},
29+
"dependencies": {
30+
"@vitest/test-dep-conditions-indirect": "file:../test-dep-conditions-indirect"
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { test, expect } from 'vitest';
2+
import conditionCustom from '@vitest/test-dep-conditions/custom';
3+
import conditionModule from '@vitest/test-dep-conditions/module';
4+
import conditionNode from '@vitest/test-dep-conditions/node';
5+
import conditionDevelopment from '@vitest/test-dep-conditions/development';
6+
import conditionProduction from '@vitest/test-dep-conditions/production';
7+
import inline from '@vitest/test-dep-conditions/inline';
8+
import indirect from '@vitest/test-dep-conditions/indirect';
9+
10+
import { viteVersion } from 'vitest/node'
11+
const viteMajor = Number(viteVersion.split('.')[0])
12+
13+
test('conditions', () => {
14+
expect({
15+
conditionCustom,
16+
conditionModule,
17+
conditionNode,
18+
conditionDevelopment,
19+
conditionProduction,
20+
indirect
21+
}).toEqual(
22+
{
23+
conditionCustom: true,
24+
"conditionDevelopment": true,
25+
"conditionModule": viteMajor <= 5,
26+
"conditionNode": true,
27+
"conditionProduction": false,
28+
"indirect": {
29+
conditionCustom: true,
30+
"conditionDevelopment": true,
31+
"conditionModule": viteMajor <= 5 && inline,
32+
"conditionNode": true,
33+
"conditionProductioin": false,
34+
},
35+
}
36+
)
37+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { defineConfig } from "vitest/config"
2+
3+
export default defineConfig({
4+
define: {
5+
'import.meta.__IS_INLINE__': 'true',
6+
},
7+
resolve: {
8+
conditions: ['custom'],
9+
},
10+
ssr: {
11+
resolve: {
12+
conditions: ['custom'],
13+
},
14+
}
15+
})

‎test/config/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"test": "vitest --typecheck.enabled"
77
},
88
"devDependencies": {
9+
"@vitest/test-dep-conditions": "file:./deps/test-dep-conditions",
910
"tinyexec": "^0.3.2",
1011
"vite": "latest",
1112
"vitest": "workspace:*"

‎test/config/test/conditions-cli.test.ts

+39
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,49 @@ test('correctly imports external dependencies with a custom condition', async ()
5353
resolve: {
5454
conditions: ['custom'],
5555
},
56+
ssr: {
57+
resolve: {
58+
conditions: ['custom'],
59+
},
60+
},
5661
define: {
5762
TEST_CONDITION: '"custom"',
5863
},
5964
})
6065

6166
expect(stderr).toBe('')
6267
})
68+
69+
test('conditions (external)', async () => {
70+
const { stderr } = await runVitest({
71+
root: 'fixtures/conditions',
72+
})
73+
74+
expect(stderr).toBe('')
75+
})
76+
77+
test('conditions (inline direct)', async () => {
78+
const { stderr } = await runVitest({
79+
root: 'fixtures/conditions',
80+
server: {
81+
deps: {
82+
inline: ['@vitest/test-dep-conditions'],
83+
},
84+
},
85+
})
86+
87+
expect(stderr).toBe('')
88+
})
89+
90+
test('conditions (inline indirect)', async () => {
91+
const { stderr } = await runVitest({
92+
root: 'fixtures/conditions',
93+
server: {
94+
deps: {
95+
inline: ['@vitest/test-dep-conditions', '@vitest/test-dep-conditions-indirect'],
96+
},
97+
},
98+
})
99+
100+
expect(stderr).toBe('')
101+
})

0 commit comments

Comments
 (0)
Please sign in to comment.