Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: apply development|production condition on Vite 6 #7301

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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('')
})
Loading