diff --git a/packages/vitest/src/integrations/browser/server.ts b/packages/vitest/src/integrations/browser/server.ts index 63aeaf74a77d..6870c2bab68f 100644 --- a/packages/vitest/src/integrations/browser/server.ts +++ b/packages/vitest/src/integrations/browser/server.ts @@ -36,6 +36,9 @@ export async function createBrowserServer(project: WorkspaceProject, configFile: port: defaultBrowserPort, } + // browser never runs in middleware mode + server.middlewareMode = false + config.server = server config.server.fs ??= {} config.server.fs.allow = config.server.fs.allow || [] diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 00f64eaecd3c..ea8219b86f83 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -49,9 +49,12 @@ export function resolveApiServerConfig( } if (api) { - if (!api.port) + if (!api.port && !api.middlewareMode) api.port = defaultPort } + else { + api = { middlewareMode: true } + } return api } diff --git a/packages/vitest/src/node/create.ts b/packages/vitest/src/node/create.ts index a0b9dec101e8..82a8f8f62d81 100644 --- a/packages/vitest/src/node/create.ts +++ b/packages/vitest/src/node/create.ts @@ -1,11 +1,12 @@ import { resolve } from 'pathe' -import { createServer, mergeConfig } from 'vite' +import { mergeConfig } from 'vite' import type { InlineConfig as ViteInlineConfig, UserConfig as ViteUserConfig } from 'vite' import { findUp } from 'find-up' import type { UserConfig, VitestRunMode } from '../types' import { configFiles } from '../constants' import { Vitest } from './core' import { VitestPlugin } from './plugins' +import { createViteServer } from './vite' export async function createVitest(mode: VitestRunMode, options: UserConfig, viteOverrides: ViteUserConfig = {}) { const ctx = new Vitest(mode) @@ -27,13 +28,10 @@ export async function createVitest(mode: VitestRunMode, options: UserConfig, vit plugins: await VitestPlugin(options, ctx), } - const server = await createServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root }))) + const server = await createViteServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root }))) - // optimizer needs .listen() to be called - if (ctx.config.api?.port || ctx.config.deps?.optimizer?.web?.enabled || ctx.config.deps?.optimizer?.ssr?.enabled) + if (ctx.config.api?.port) await server.listen() - else - await server.pluginContainer.buildStart({}) return ctx } diff --git a/packages/vitest/src/node/logger.ts b/packages/vitest/src/node/logger.ts index 76ee78cb8264..bd18b30861f4 100644 --- a/packages/vitest/src/node/logger.ts +++ b/packages/vitest/src/node/logger.ts @@ -139,7 +139,7 @@ export class Logger { if (this.ctx.config.ui) this.log(c.dim(c.green(` UI started at http://${this.ctx.config.api?.host || 'localhost'}:${c.bold(`${this.ctx.server.config.server.port}`)}${this.ctx.config.uiBase}`))) - else if (this.ctx.config.api) + else if (this.ctx.config.api?.port) this.log(c.dim(c.green(` API started at http://${this.ctx.config.api?.host || 'localhost'}:${c.bold(`${this.ctx.config.api.port}`)}`))) if (this.ctx.coverageProvider) diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index 5004a8c87d22..e3f11a49261e 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -57,7 +57,7 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t ;(options as ResolvedConfig).defines = defines - let open: string | boolean | undefined + let open: string | boolean | undefined = false if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? '/__vitest__/' diff --git a/packages/vitest/src/node/plugins/workspace.ts b/packages/vitest/src/node/plugins/workspace.ts index ea291ad41331..91f60af4dc04 100644 --- a/packages/vitest/src/node/plugins/workspace.ts +++ b/packages/vitest/src/node/plugins/workspace.ts @@ -70,6 +70,7 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp open: false, hmr: false, preTransformRequests: false, + middlewareMode: true, fs: { allow: resolveFsAllow( project.ctx.config.root, diff --git a/packages/vitest/src/node/vite.ts b/packages/vitest/src/node/vite.ts new file mode 100644 index 000000000000..4138d3b1fc8b --- /dev/null +++ b/packages/vitest/src/node/vite.ts @@ -0,0 +1,21 @@ +import type { InlineConfig } from 'vite' +import { createServer } from 'vite' + +export async function createViteServer(inlineConfig: InlineConfig) { + // Vite prints an error (https://github.com/vitejs/vite/issues/14328) + // But Vitest works correctly either way + const error = console.error + console.error = (...args: any[]) => { + if (typeof args[0] === 'string' && args[0].includes('WebSocket server error:')) + return + error(...args) + } + + const server = await createServer({ + logLevel: 'error', + ...inlineConfig, + }) + + console.error = error + return server +} diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index 9a41650eef5b..02a3ce48d4e4 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -2,7 +2,6 @@ import { promises as fs } from 'node:fs' import fg from 'fast-glob' import mm from 'micromatch' import { dirname, relative, resolve, toNamespacedPath } from 'pathe' -import { createServer } from 'vite' import type { ViteDevServer, InlineConfig as ViteInlineConfig } from 'vite' import { ViteNodeRunner } from 'vite-node/client' import { ViteNodeServer } from 'vite-node/server' @@ -14,6 +13,7 @@ import type { BrowserProvider } from '../types/browser' import { getBrowserProvider } from '../integrations/browser' import { isBrowserEnabled, resolveConfig } from './config' import { WorkspaceVitestPlugin } from './plugins/workspace' +import { createViteServer } from './vite' interface InitializeProjectOptions extends UserWorkspaceConfig { workspaceConfigPath: string @@ -44,13 +44,7 @@ export async function initializeProject(workspacePath: string | number, ctx: Vit ], } - const server = await createServer(config) - - // optimizer needs .listen() to be called - if (ctx.config.api?.port || project.config.deps?.optimizer?.web?.enabled || project.config.deps?.optimizer?.ssr?.enabled) - await server.listen() - else - await server.pluginContainer.buildStart({}) + await createViteServer(config) return project } diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index 7a40bd320d6d..6763cc938899 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -1,4 +1,4 @@ -import type { AliasOptions, CommonServerOptions, DepOptimizationConfig } from 'vite' +import type { AliasOptions, DepOptimizationConfig, ServerOptions } from 'vite' import type { PrettyFormatOptions } from 'pretty-format' import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' import type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner' @@ -23,7 +23,7 @@ export type VitestEnvironment = BuiltinEnvironment | (string & Record +export type ApiConfig = Pick export type { JSDOMOptions, HappyDOMOptions } diff --git a/test/core/package.json b/test/core/package.json index 998f1603a476..5a03728d28cb 100644 --- a/test/core/package.json +++ b/test/core/package.json @@ -3,6 +3,7 @@ "private": true, "scripts": { "test": "vitest", + "dev": "vite", "coverage": "vitest run --coverage" }, "devDependencies": { diff --git a/test/core/vitest.config.ts b/test/core/vite.config.ts similarity index 98% rename from test/core/vitest.config.ts rename to test/core/vite.config.ts index 03a6bec0c909..ff4e8cdc2635 100644 --- a/test/core/vitest.config.ts +++ b/test/core/vite.config.ts @@ -41,6 +41,9 @@ export default defineConfig({ { find: /^inline-lib$/, replacement: resolve(__dirname, 'projects', 'inline-lib') }, ], }, + server: { + port: 3022, + }, test: { name: 'core', exclude: ['**/fixtures/**', '**/vm-wasm.test.ts', ...defaultExclude],