Skip to content

Commit

Permalink
fix: apply development|production condition on Vite 6 (#7301)
Browse files Browse the repository at this point in the history
Co-authored-by: Vladimir Sheremet <[email protected]>
  • Loading branch information
hi-ogawa and sheremet-va authored Jan 23, 2025
1 parent 0b404e5 commit ef1464f
Show file tree
Hide file tree
Showing 18 changed files with 233 additions and 25 deletions.
4 changes: 4 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ expect(() => {

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

### `module` condition export is not resolved by default on Vite 6

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.

### `Custom` Type is Deprecated <Badge type="danger">API</Badge> {#custom-type-is-deprecated}

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`:
Expand Down
15 changes: 5 additions & 10 deletions packages/vitest/src/node/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { VitestOptimizer } from './optimizer'
import { SsrReplacerPlugin } from './ssrReplacer'
import {
deleteDefineConfig,
getDefaultResolveOptions,
hijackVitePluginInject,
resolveFsAllow,
} from './utils'
Expand Down Expand Up @@ -73,6 +74,8 @@ export async function VitestPlugin(
open = testConfig.uiBase ?? '/__vitest__/'
}

const resolveOptions = getDefaultResolveOptions()

const config: ViteConfig = {
root: viteConfig.test?.root || options.root,
esbuild:
Expand All @@ -86,11 +89,8 @@ export async function VitestPlugin(
legalComments: 'inline',
},
resolve: {
// by default Vite resolves `module` field, which not always a native ESM module
// setting this option can bypass that and fallback to cjs version
mainFields: [],
...resolveOptions,
alias: testConfig.alias,
conditions: ['node'],
},
server: {
...testConfig.api,
Expand All @@ -115,12 +115,7 @@ export async function VitestPlugin(
// @ts-ignore Vite 6 compat
environments: {
ssr: {
resolve: {
// by default Vite resolves `module` field, which not always a native ESM module
// setting this option can bypass that and fallback to cjs version
mainFields: [],
conditions: ['node'],
},
resolve: resolveOptions,
},
},
test: {
Expand Down
21 changes: 21 additions & 0 deletions packages/vitest/src/node/plugins/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
import type { DepsOptimizationOptions, InlineConfig } from '../types/config'
import { dirname } from 'pathe'
import { searchForWorkspaceRoot, version as viteVersion } from 'vite'
import * as vite from 'vite'
import { rootDir } from '../../paths'
import { VitestCache } from '../cache'

Expand Down Expand Up @@ -147,3 +148,23 @@ export function resolveFsAllow(
rootDir,
]
}

export function getDefaultResolveOptions(): vite.ResolveOptions {
return {
// by default Vite resolves `module` field, which is not always a native ESM module
// setting this option can bypass that and fallback to cjs version
mainFields: [],
// same for `module` condition and Vite 5 doesn't even allow excluding it,
// but now it's possible since Vite 6.
conditions: getDefaultServerConditions(),
}
}

function getDefaultServerConditions(): string[] {
const viteMajor = Number(viteVersion.split('.')[0])
if (viteMajor >= 6) {
const conditions: string[] = (vite as any).defaultServerConditions
return conditions.filter(c => c !== 'module')
}
return ['node']
}
14 changes: 4 additions & 10 deletions packages/vitest/src/node/plugins/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { VitestOptimizer } from './optimizer'
import { SsrReplacerPlugin } from './ssrReplacer'
import {
deleteDefineConfig,
getDefaultResolveOptions,
hijackVitePluginInject,
resolveFsAllow,
} from './utils'
Expand Down Expand Up @@ -92,14 +93,12 @@ export function WorkspaceVitestPlugin(
}
}

const resolveOptions = getDefaultResolveOptions()
const config: ViteConfig = {
root,
resolve: {
// by default Vite resolves `module` field, which not always a native ESM module
// setting this option can bypass that and fallback to cjs version
mainFields: [],
...resolveOptions,
alias: testConfig.alias,
conditions: ['node'],
},
esbuild: viteConfig.esbuild === false
? false
Expand Down Expand Up @@ -130,12 +129,7 @@ export function WorkspaceVitestPlugin(
// @ts-ignore Vite 6 compat
environments: {
ssr: {
resolve: {
// by default Vite resolves `module` field, which not always a native ESM module
// setting this option can bypass that and fallback to cjs version
mainFields: [],
conditions: ['node'],
},
resolve: resolveOptions,
},
},
test: {
Expand Down
20 changes: 15 additions & 5 deletions packages/vitest/src/node/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { TestSpecification } from './spec'
import type { BuiltinPool, Pool } from './types/pool-options'
import { isatty } from 'node:tty'
import mm from 'micromatch'
import { version as viteVersion } from 'vite'
import { isWindows } from '../utils/env'
import { createForksPool } from './pools/forks'
import { createThreadsPool } from './pools/threads'
Expand Down Expand Up @@ -91,11 +92,14 @@ export function createPool(ctx: Vitest): ProcessPool {

// in addition to resolve.conditions Vite also adds production/development,
// see: https://github.com/vitejs/vite/blob/af2aa09575229462635b7cbb6d248ca853057ba2/packages/vite/src/node/plugins/resolve.ts#L1056-L1080
const potentialConditions = new Set([
'production',
'development',
...ctx.vite.config.resolve.conditions,
])
const viteMajor = Number(viteVersion.split('.')[0])
const potentialConditions = new Set(viteMajor >= 6
? (ctx.vite.config.ssr.resolve?.conditions ?? [])
: [
'production',
'development',
...ctx.vite.config.resolve.conditions,
])
const conditions = [...potentialConditions]
.filter((condition) => {
if (condition === 'production') {
Expand All @@ -106,6 +110,12 @@ export function createPool(ctx: Vitest): ProcessPool {
}
return true
})
.map((condition) => {
if (viteMajor >= 6 && condition === 'development|production') {
return ctx.vite.config.isProduction ? 'production' : 'development'
}
return condition
})
.flatMap(c => ['--conditions', c])

// Instead of passing whole process.execArgv to the workers, pick allowed options.
Expand Down
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/config/deps/test-dep-conditions-indirect/false.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default false
27 changes: 27 additions & 0 deletions test/config/deps/test-dep-conditions-indirect/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@vitest/test-dep-conditions-indirect",
"type": "module",
"private": true,
"exports": {
"./custom": {
"custom": "./true.js",
"default": "./false.js"
},
"./module": {
"module": "./true.js",
"default": "./false.js"
},
"./node": {
"node": "./true.js",
"default": "./false.js"
},
"./development": {
"development": "./true.js",
"default": "./false.js"
},
"./production": {
"production": "./true.js",
"default": "./false.js"
}
}
}
1 change: 1 addition & 0 deletions test/config/deps/test-dep-conditions-indirect/true.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default true
1 change: 1 addition & 0 deletions test/config/deps/test-dep-conditions/false.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default false
13 changes: 13 additions & 0 deletions test/config/deps/test-dep-conditions/indirect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import conditionCustom from '@vitest/test-dep-conditions-indirect/custom'
import conditionDevelopment from '@vitest/test-dep-conditions-indirect/development'
import conditionModule from '@vitest/test-dep-conditions-indirect/module'
import conditionNode from '@vitest/test-dep-conditions-indirect/node'
import conditionProductioin from '@vitest/test-dep-conditions-indirect/production'

export default {
conditionCustom,
conditionModule,
conditionNode,
conditionDevelopment,
conditionProductioin,
}
1 change: 1 addition & 0 deletions test/config/deps/test-dep-conditions/inline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default !!import.meta.__IS_INLINE__
32 changes: 32 additions & 0 deletions test/config/deps/test-dep-conditions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@vitest/test-dep-conditions",
"type": "module",
"private": true,
"exports": {
"./custom": {
"custom": "./true.js",
"default": "./false.js"
},
"./module": {
"module": "./true.js",
"default": "./false.js"
},
"./node": {
"node": "./true.js",
"default": "./false.js"
},
"./development": {
"development": "./true.js",
"default": "./false.js"
},
"./production": {
"production": "./true.js",
"default": "./false.js"
},
"./inline": "./inline.js",
"./indirect": "./indirect.js"
},
"dependencies": {
"@vitest/test-dep-conditions-indirect": "file:../test-dep-conditions-indirect"
}
}
1 change: 1 addition & 0 deletions test/config/deps/test-dep-conditions/true.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default true
37 changes: 37 additions & 0 deletions test/config/fixtures/conditions/basic.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { test, expect } from 'vitest';
import conditionCustom from '@vitest/test-dep-conditions/custom';
import conditionModule from '@vitest/test-dep-conditions/module';
import conditionNode from '@vitest/test-dep-conditions/node';
import conditionDevelopment from '@vitest/test-dep-conditions/development';
import conditionProduction from '@vitest/test-dep-conditions/production';
import inline from '@vitest/test-dep-conditions/inline';
import indirect from '@vitest/test-dep-conditions/indirect';

import { viteVersion } from 'vitest/node'
const viteMajor = Number(viteVersion.split('.')[0])

test('conditions', () => {
expect({
conditionCustom,
conditionModule,
conditionNode,
conditionDevelopment,
conditionProduction,
indirect
}).toEqual(
{
conditionCustom: true,
"conditionDevelopment": true,
"conditionModule": viteMajor <= 5,
"conditionNode": true,
"conditionProduction": false,
"indirect": {
conditionCustom: true,
"conditionDevelopment": true,
"conditionModule": viteMajor <= 5 && inline,
"conditionNode": true,
"conditionProductioin": false,
},
}
)
})
15 changes: 15 additions & 0 deletions test/config/fixtures/conditions/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from "vitest/config"

export default defineConfig({
define: {
'import.meta.__IS_INLINE__': 'true',
},
resolve: {
conditions: ['custom'],
},
ssr: {
resolve: {
conditions: ['custom'],
},
}
})
1 change: 1 addition & 0 deletions test/config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"test": "vitest --typecheck.enabled"
},
"devDependencies": {
"@vitest/test-dep-conditions": "file:./deps/test-dep-conditions",
"tinyexec": "^0.3.2",
"vite": "latest",
"vitest": "workspace:*"
Expand Down
39 changes: 39 additions & 0 deletions test/config/test/conditions-cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,49 @@ test('correctly imports external dependencies with a custom condition', async ()
resolve: {
conditions: ['custom'],
},
ssr: {
resolve: {
conditions: ['custom'],
},
},
define: {
TEST_CONDITION: '"custom"',
},
})

expect(stderr).toBe('')
})

test('conditions (external)', async () => {
const { stderr } = await runVitest({
root: 'fixtures/conditions',
})

expect(stderr).toBe('')
})

test('conditions (inline direct)', async () => {
const { stderr } = await runVitest({
root: 'fixtures/conditions',
server: {
deps: {
inline: ['@vitest/test-dep-conditions'],
},
},
})

expect(stderr).toBe('')
})

test('conditions (inline indirect)', async () => {
const { stderr } = await runVitest({
root: 'fixtures/conditions',
server: {
deps: {
inline: ['@vitest/test-dep-conditions', '@vitest/test-dep-conditions-indirect'],
},
},
})

expect(stderr).toBe('')
})

0 comments on commit ef1464f

Please sign in to comment.