diff --git a/docs/.vitepress/scripts/cli-generator.ts b/docs/.vitepress/scripts/cli-generator.ts index 4f3ba4fe06cb..bea3ade8f6a9 100644 --- a/docs/.vitepress/scripts/cli-generator.ts +++ b/docs/.vitepress/scripts/cli-generator.ts @@ -30,6 +30,7 @@ const skipConfig = new Set([ 'coverage.thresholds.lines', 'standalone', 'clearScreen', + 'configLoader', 'color', 'run', 'hideSkippedTests', diff --git a/docs/advanced/api/index.md b/docs/advanced/api/index.md index 1f85b52e83b8..8e6ab4cdfdd7 100644 --- a/docs/advanced/api/index.md +++ b/docs/advanced/api/index.md @@ -61,7 +61,7 @@ The ["Running Tests"](/advanced/guide/tests#startvitest) guide has a usage examp ```ts function createVitest( mode: VitestRunMode, - options: UserConfig, + options: CliOptions, viteOverrides: ViteUserConfig = {}, vitestOptions: VitestOptions = {}, ): Promise diff --git a/docs/guide/cli-generated.md b/docs/guide/cli-generated.md index 199653c9703e..f0572dc3c15f 100644 --- a/docs/guide/cli-generated.md +++ b/docs/guide/cli-generated.md @@ -919,6 +919,12 @@ Removes colors from the console output Clear terminal screen when re-running tests during watch mode (default: `true`) +### configLoader + +- **CLI:** `--configLoader ` + +Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly. This is only available in vite version 6.1.0 and above. (default: `bundle`) + ### standalone - **CLI:** `--standalone` diff --git a/packages/browser/src/node/index.ts b/packages/browser/src/node/index.ts index 69e598d752a3..f124c92b5d76 100644 --- a/packages/browser/src/node/index.ts +++ b/packages/browser/src/node/index.ts @@ -58,6 +58,7 @@ export async function createBrowserServer( }, mode: project.config.mode, configFile: configPath, + configLoader: project.vite.config.inlineConfig.configLoader, // watch is handled by Vitest server: { hmr: false, diff --git a/packages/vitest/src/node/cli/cli-api.ts b/packages/vitest/src/node/cli/cli-api.ts index 2e79009f0998..e6944c4d192c 100644 --- a/packages/vitest/src/node/cli/cli-api.ts +++ b/packages/vitest/src/node/cli/cli-api.ts @@ -1,4 +1,4 @@ -import type { UserConfig as ViteUserConfig } from 'vite' +import type { InlineConfig as ViteInlineConfig, UserConfig as ViteUserConfig } from 'vite' import type { environments } from '../../integrations/env' import type { Vitest, VitestOptions } from '../core' import type { TestModule, TestSuite } from '../reporters/reported-tasks' @@ -28,6 +28,14 @@ export interface CliOptions extends UserConfig { * Output collected test files only */ filesOnly?: boolean + + /** + * Override vite config's configLoader from cli. + * Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly (default: `bundle`). + * This is only available with **vite version 6.1.0** and above. + * @experimental + */ + configLoader?: ViteInlineConfig extends { configLoader?: infer T } ? T : never } /** diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 0bfd6b828f78..c688d8fee693 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -806,6 +806,11 @@ export const cliOptionsConfig: VitestCLIOptions = { description: 'Clear terminal screen when re-running tests during watch mode (default: `true`)', }, + configLoader: { + description: + 'Use `bundle` to bundle the config with esbuild or `runner` (experimental) to process it on the fly. This is only available in vite version 6.1.0 and above. (default: `bundle`)', + argument: '', + }, standalone: { description: 'Start Vitest without running tests. File filters will be ignored, tests will be running only on change (default: `false`)', diff --git a/packages/vitest/src/node/create.ts b/packages/vitest/src/node/create.ts index 8d0fe76a8949..078362168b9a 100644 --- a/packages/vitest/src/node/create.ts +++ b/packages/vitest/src/node/create.ts @@ -2,8 +2,9 @@ import type { InlineConfig as ViteInlineConfig, UserConfig as ViteUserConfig, } from 'vite' +import type { CliOptions } from './cli/cli-api' import type { VitestOptions } from './core' -import type { UserConfig, VitestRunMode } from './types/config' +import type { VitestRunMode } from './types/config' import { resolve } from 'node:path' import { slash } from '@vitest/utils' import { findUp } from 'find-up' @@ -15,7 +16,7 @@ import { createViteServer } from './vite' export async function createVitest( mode: VitestRunMode, - options: UserConfig, + options: CliOptions, viteOverrides: ViteUserConfig = {}, vitestOptions: VitestOptions = {}, ): Promise { @@ -33,6 +34,7 @@ export async function createVitest( const config: ViteInlineConfig = { configFile: configPath, + configLoader: options.configLoader, // this will make "mode": "test" | "benchmark" inside defineConfig mode: options.mode || mode, plugins: await VitestPlugin(options, ctx), diff --git a/packages/vitest/src/node/project.ts b/packages/vitest/src/node/project.ts index 3a41fb743d22..75075e47398d 100644 --- a/packages/vitest/src/node/project.ts +++ b/packages/vitest/src/node/project.ts @@ -742,6 +742,7 @@ export async function initializeProject( const config: ViteInlineConfig = { ...restOptions, configFile, + configLoader: ctx.vite.config.inlineConfig.configLoader, // this will make "mode": "test" | "benchmark" inside defineConfig mode: options.test?.mode || options.mode || ctx.config.mode, plugins: [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f525db68e8fb..c228c0f48118 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1228,6 +1228,9 @@ importers: '@vitest/test-dep-error': specifier: file:./deps/error version: file:test/cli/deps/error + '@vitest/test-dep-linked': + specifier: link:./deps/linked + version: link:deps/linked '@vitest/utils': specifier: workspace:* version: link:../../packages/utils diff --git a/test/cli/deps/linked/index.ts b/test/cli/deps/linked/index.ts new file mode 100644 index 000000000000..b7ba2a6aa957 --- /dev/null +++ b/test/cli/deps/linked/index.ts @@ -0,0 +1 @@ +export default 'ok' satisfies string diff --git a/test/cli/deps/linked/package.json b/test/cli/deps/linked/package.json new file mode 100644 index 000000000000..47df26633a08 --- /dev/null +++ b/test/cli/deps/linked/package.json @@ -0,0 +1,8 @@ +{ + "name": "@vitest/test-dep-linked", + "type": "module", + "private": true, + "exports": { + "./ts": "./index.ts" + } +} diff --git a/test/cli/fixtures/config-loader/browser/basic.test.ts b/test/cli/fixtures/config-loader/browser/basic.test.ts new file mode 100644 index 000000000000..7912813330eb --- /dev/null +++ b/test/cli/fixtures/config-loader/browser/basic.test.ts @@ -0,0 +1,3 @@ +import { test } from "vitest" + +test("browser ok", () => {}) diff --git a/test/cli/fixtures/config-loader/browser/vitest.config.ts b/test/cli/fixtures/config-loader/browser/vitest.config.ts new file mode 100644 index 000000000000..d5b0934988d7 --- /dev/null +++ b/test/cli/fixtures/config-loader/browser/vitest.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vitest/config" +import "@vitest/test-dep-linked/ts"; + +export default defineConfig({ + test: { + browser: { + enabled: true, + provider: 'playwright', + headless: true, + instances: [ + { + browser: 'chromium', + } + ] + } + } +}) diff --git a/test/cli/fixtures/config-loader/node/basic.test.ts b/test/cli/fixtures/config-loader/node/basic.test.ts new file mode 100644 index 000000000000..626cbce5d8f5 --- /dev/null +++ b/test/cli/fixtures/config-loader/node/basic.test.ts @@ -0,0 +1,3 @@ +import { test } from "vitest" + +test("node ok", () => {}) diff --git a/test/cli/fixtures/config-loader/node/vitest.config.ts b/test/cli/fixtures/config-loader/node/vitest.config.ts new file mode 100644 index 000000000000..7cd505689a86 --- /dev/null +++ b/test/cli/fixtures/config-loader/node/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from "vitest/config" +import "@vitest/test-dep-linked/ts"; + +export default defineConfig({}) diff --git a/test/cli/fixtures/config-loader/vitest.config.ts b/test/cli/fixtures/config-loader/vitest.config.ts new file mode 100644 index 000000000000..44880bd59c28 --- /dev/null +++ b/test/cli/fixtures/config-loader/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "vitest/config" +import "@vitest/test-dep-linked/ts"; + +export default defineConfig({ + test: { + workspace: [ + "browser/vitest.config.ts", + "node/vitest.config.ts", + ], + }, +}) diff --git a/test/cli/package.json b/test/cli/package.json index c448f9ca8e80..3ef8e2a9a3c5 100644 --- a/test/cli/package.json +++ b/test/cli/package.json @@ -11,6 +11,7 @@ "@vitejs/plugin-basic-ssl": "^1.2.0", "@vitest/runner": "workspace:^", "@vitest/test-dep-error": "file:./deps/error", + "@vitest/test-dep-linked": "link:./deps/linked", "@vitest/utils": "workspace:*", "debug": "^4.4.0", "unplugin-swc": "^1.5.1", diff --git a/test/cli/test/config-loader.test.ts b/test/cli/test/config-loader.test.ts new file mode 100644 index 000000000000..1a5f85b32afb --- /dev/null +++ b/test/cli/test/config-loader.test.ts @@ -0,0 +1,26 @@ +import { expect, test } from 'vitest' +import { runVitestCli } from '../../test-utils' + +test('configLoader default', async () => { + const { vitest, exitCode } = await runVitestCli( + 'run', + '--root', + 'fixtures/config-loader', + ) + expect(vitest.stderr).toContain('failed to load config') + expect(exitCode).not.toBe(0) +}) + +test('configLoader runner', async () => { + const { vitest, exitCode } = await runVitestCli( + 'run', + '--root', + 'fixtures/config-loader', + '--configLoader', + 'runner', + ) + expect(vitest.stderr).toBe('') + expect(vitest.stdout).toContain('✓ node') + expect(vitest.stdout).toContain('✓ browser (chromium)') + expect(exitCode).toBe(0) +})