diff --git a/.changeset/slimy-mice-dance.md b/.changeset/slimy-mice-dance.md
new file mode 100644
index 000000000000..cfe2aa036220
--- /dev/null
+++ b/.changeset/slimy-mice-dance.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes use of Vitest with Astro 5
diff --git a/packages/astro/package.json b/packages/astro/package.json
index f3d3d38cce79..15d6640a0e3b 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -224,7 +224,8 @@
"rollup": "^4.21.2",
"sass": "^1.78.0",
"undici": "^6.19.8",
- "unified": "^11.0.5"
+ "unified": "^11.0.5",
+ "vitest": "^2.1.1"
},
"engines": {
"node": "^18.17.1 || ^20.3.0 || >=21.0.0",
diff --git a/packages/astro/src/config/index.ts b/packages/astro/src/config/index.ts
index 82f5d77c83ca..77c33fcc5ffc 100644
--- a/packages/astro/src/config/index.ts
+++ b/packages/astro/src/config/index.ts
@@ -2,6 +2,7 @@ import type { UserConfig as ViteUserConfig } from 'vite';
import { Logger } from '../core/logger/core.js';
import { createRouteManifest } from '../core/routing/index.js';
import type { AstroInlineConfig, AstroUserConfig } from '../types/public/config.js';
+import { createDevelopmentManifest } from '../vite-plugin-astro-server/plugin.js';
export function defineConfig(config: AstroUserConfig) {
return config;
@@ -12,7 +13,7 @@ export function getViteConfig(
inlineAstroConfig: AstroInlineConfig = {},
) {
// Return an async Vite config getter which exposes a resolved `mode` and `command`
- return async ({ mode, command }: { mode: string; command: 'serve' | 'build' }) => {
+ return async ({ mode, command }: { mode: 'dev'; command: 'serve' | 'build' }) => {
// Vite `command` is `serve | build`, but Astro uses `dev | build`
const cmd = command === 'serve' ? 'dev' : command;
@@ -42,6 +43,7 @@ export function getViteConfig(
let settings = await createSettings(config, userViteConfig.root);
settings = await runHookConfigSetup({ settings, command: cmd, logger });
const manifest = await createRouteManifest({ settings }, logger);
+ const devSSRManifest = createDevelopmentManifest(settings);
const viteConfig = await createVite(
{
mode,
@@ -50,7 +52,7 @@ export function getViteConfig(
astroContentListenPlugin({ settings, logger, fs }),
],
},
- { settings, logger, mode, sync: false, manifest },
+ { settings, logger, mode, sync: false, manifest, ssrManifest: devSSRManifest },
);
await runHookConfigDone({ settings, logger });
return mergeConfig(viteConfig, userViteConfig);
diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts
index eb27657271bb..d0e4566581d7 100644
--- a/packages/astro/src/core/create-vite.ts
+++ b/packages/astro/src/core/create-vite.ts
@@ -41,17 +41,21 @@ import { joinPaths } from './path.js';
import { vitePluginServerIslands } from './server-islands/vite-plugin-server-islands.js';
import { isObject } from './util.js';
-interface CreateViteOptions {
+type CreateViteOptions = {
settings: AstroSettings;
logger: Logger;
- mode: 'dev' | 'build' | string;
// will be undefined when using `getViteConfig`
command?: 'dev' | 'build';
fs?: typeof nodeFs;
sync: boolean;
manifest: ManifestData;
+} & ({
+ mode: 'dev';
+ ssrManifest: SSRManifest;
+} | {
+ mode: 'build';
ssrManifest?: SSRManifest;
-}
+});
const ALWAYS_NOEXTERNAL = [
// This is only because Vite's native ESM doesn't resolve "exports" correctly.
@@ -134,8 +138,8 @@ export async function createVite(
astroScriptsPlugin({ settings }),
// The server plugin is for dev only and having it run during the build causes
// the build to run very slow as the filewatcher is triggered often.
- mode !== 'build' &&
- vitePluginAstroServer({ settings, logger, fs, manifest, ssrManifest: ssrManifest! }), // ssrManifest is only required in dev mode, where it gets created before a Vite instance is created, and get passed to this function
+ mode === 'dev' &&
+ vitePluginAstroServer({ settings, logger, fs, manifest, ssrManifest }), // ssrManifest is only required in dev mode, where it gets created before a Vite instance is created, and get passed to this function
envVitePlugin({ settings }),
astroEnv({ settings, mode, sync }),
markdownVitePlugin({ settings, logger }),
diff --git a/packages/astro/test/fixtures/vitest/astro.config.mjs b/packages/astro/test/fixtures/vitest/astro.config.mjs
new file mode 100644
index 000000000000..a8ce50d378e6
--- /dev/null
+++ b/packages/astro/test/fixtures/vitest/astro.config.mjs
@@ -0,0 +1,5 @@
+import { defineConfig } from 'astro/config';
+
+export default defineConfig({
+ output: "static",
+});
diff --git a/packages/astro/test/fixtures/vitest/package.json b/packages/astro/test/fixtures/vitest/package.json
new file mode 100644
index 000000000000..c2919c61a21b
--- /dev/null
+++ b/packages/astro/test/fixtures/vitest/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "@test/vitest",
+ "version": "0.0.0",
+ "type": "module",
+ "private": true,
+ "scripts": {
+ "test": "vitest run"
+ },
+ "dependencies": {
+ "astro": "workspace:*",
+ "vitest": "^2.1.1"
+ }
+}
diff --git a/packages/astro/test/fixtures/vitest/src/components/hello.spec.ts b/packages/astro/test/fixtures/vitest/src/components/hello.spec.ts
new file mode 100644
index 000000000000..1b6ec465ccdb
--- /dev/null
+++ b/packages/astro/test/fixtures/vitest/src/components/hello.spec.ts
@@ -0,0 +1,5 @@
+import { expect, test } from 'vitest';
+
+test('sup', () => {
+ expect(true).toBeTruthy();
+})
diff --git a/packages/astro/test/fixtures/vitest/src/pages/index.astro b/packages/astro/test/fixtures/vitest/src/pages/index.astro
new file mode 100644
index 000000000000..c215aceaa876
--- /dev/null
+++ b/packages/astro/test/fixtures/vitest/src/pages/index.astro
@@ -0,0 +1,7 @@
+
+
+ testing
+
+
+
+
diff --git a/packages/astro/test/fixtures/vitest/vitest.config.js b/packages/astro/test/fixtures/vitest/vitest.config.js
new file mode 100644
index 000000000000..c756df5f24fd
--- /dev/null
+++ b/packages/astro/test/fixtures/vitest/vitest.config.js
@@ -0,0 +1,8 @@
+///
+import { getViteConfig } from 'astro/config';
+
+export default getViteConfig({
+ test: {
+ // Vitest configuration options
+ },
+});
diff --git a/packages/astro/test/vitest.test.js b/packages/astro/test/vitest.test.js
new file mode 100644
index 000000000000..6c07b5b05727
--- /dev/null
+++ b/packages/astro/test/vitest.test.js
@@ -0,0 +1,25 @@
+
+import assert from 'node:assert/strict';
+import { describe, it } from 'node:test';
+import { fileURLToPath } from 'node:url';
+import { createVitest } from 'vitest/node'
+
+describe('vitest', () => {
+ it('basics', async () => {
+ const config = new URL('./fixtures/vitest/vitest.config.js', import.meta.url);
+
+ const vitest = await createVitest('test', {
+ config: fileURLToPath(config),
+ root: fileURLToPath(new URL('./fixtures/vitest/', import.meta.url)),
+ watch: false
+ });
+
+ try {
+ await vitest.start();
+ } catch(_) {
+ assert.ok(false, 'test failed');
+ } finally {
+ await vitest.close();
+ }
+ });
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cbd165a4390f..ea58b216e087 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -839,6 +839,9 @@ importers:
unified:
specifier: ^11.0.5
version: 11.0.5
+ vitest:
+ specifier: ^2.1.1
+ version: 2.1.1(@types/node@18.19.31)(jsdom@23.2.0)(sass@1.78.0)
packages/astro-prism:
dependencies:
@@ -4158,6 +4161,15 @@ importers:
specifier: workspace:*
version: link:../../..
+ packages/astro/test/fixtures/vitest:
+ dependencies:
+ astro:
+ specifier: workspace:*
+ version: link:../../..
+ vitest:
+ specifier: ^2.1.1
+ version: 2.1.1(@types/node@18.19.31)(jsdom@23.2.0)(sass@1.78.0)
+
packages/astro/test/fixtures/vue-component:
dependencies:
'@astrojs/vue':
@@ -7187,21 +7199,50 @@ packages:
'@vitest/expect@2.0.5':
resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==}
+ '@vitest/expect@2.1.1':
+ resolution: {integrity: sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==}
+
+ '@vitest/mocker@2.1.1':
+ resolution: {integrity: sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==}
+ peerDependencies:
+ msw: ^2.3.5
+ vite: ^5.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
'@vitest/pretty-format@2.0.5':
resolution: {integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==}
+ '@vitest/pretty-format@2.1.1':
+ resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==}
+
'@vitest/runner@2.0.5':
resolution: {integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==}
+ '@vitest/runner@2.1.1':
+ resolution: {integrity: sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==}
+
'@vitest/snapshot@2.0.5':
resolution: {integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==}
+ '@vitest/snapshot@2.1.1':
+ resolution: {integrity: sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==}
+
'@vitest/spy@2.0.5':
resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==}
+ '@vitest/spy@2.1.1':
+ resolution: {integrity: sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==}
+
'@vitest/utils@2.0.5':
resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==}
+ '@vitest/utils@2.1.1':
+ resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==}
+
'@volar/kit@2.4.0':
resolution: {integrity: sha512-uqwtPKhrbnP+3f8hs+ltDYXLZ6Wdbs54IzkaPocasI4aBhqWLht5qXctE1MqpZU52wbH359E0u9nhxEFmyon+w==}
peerDependencies:
@@ -7687,7 +7728,7 @@ packages:
resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==}
concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
consola@3.2.3:
resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
@@ -8765,10 +8806,12 @@ packages:
libsql@0.3.19:
resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==}
+ cpu: [x64, arm64, wasm32]
os: [darwin, linux, win32]
libsql@0.4.1:
resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==}
+ cpu: [x64, arm64, wasm32]
os: [darwin, linux, win32]
lilconfig@2.1.0:
@@ -10330,6 +10373,9 @@ packages:
tinybench@2.8.0:
resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
tinyexec@0.3.0:
resolution: {integrity: sha512-tVGE0mVJPGb0chKhqmsoosjsS+qUnJVGJpZgsHYQcGoPlG3B51R3PouqTgEGH2Dc9jjFyOqOpix6ZHNMXp1FZg==}
@@ -10627,6 +10673,11 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
+ vite-node@2.1.1:
+ resolution: {integrity: sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
vite-plugin-inspect@0.8.7:
resolution: {integrity: sha512-/XXou3MVc13A5O9/2Nd6xczjrUwt7ZyI9h8pTnUMkr5SshLcb0PJUOVq2V+XVkdeU4njsqAtmK87THZuO2coGA==}
engines: {node: '>=14'}
@@ -10735,6 +10786,31 @@ packages:
jsdom:
optional: true
+ vitest@2.1.1:
+ resolution: {integrity: sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 2.1.1
+ '@vitest/ui': 2.1.1
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
volar-service-css@0.0.61:
resolution: {integrity: sha512-Ct9L/w+IB1JU8F4jofcNCGoHy6TF83aiapfZq9A0qYYpq+Kk5dH+ONS+rVZSsuhsunq8UvAuF8Gk6B8IFLfniw==}
peerDependencies:
@@ -12781,25 +12857,59 @@ snapshots:
chai: 5.1.1
tinyrainbow: 1.2.0
+ '@vitest/expect@2.1.1':
+ dependencies:
+ '@vitest/spy': 2.1.1
+ '@vitest/utils': 2.1.1
+ chai: 5.1.1
+ tinyrainbow: 1.2.0
+
+ '@vitest/mocker@2.1.1(vite@5.4.3(@types/node@18.19.31)(sass@1.78.0))':
+ dependencies:
+ '@vitest/spy': 2.1.1
+ estree-walker: 3.0.3
+ magic-string: 0.30.11
+ optionalDependencies:
+ vite: 5.4.3(@types/node@18.19.31)(sass@1.78.0)
+
'@vitest/pretty-format@2.0.5':
dependencies:
tinyrainbow: 1.2.0
+ '@vitest/pretty-format@2.1.1':
+ dependencies:
+ tinyrainbow: 1.2.0
+
'@vitest/runner@2.0.5':
dependencies:
'@vitest/utils': 2.0.5
pathe: 1.1.2
+ '@vitest/runner@2.1.1':
+ dependencies:
+ '@vitest/utils': 2.1.1
+ pathe: 1.1.2
+
'@vitest/snapshot@2.0.5':
dependencies:
'@vitest/pretty-format': 2.0.5
magic-string: 0.30.11
pathe: 1.1.2
+ '@vitest/snapshot@2.1.1':
+ dependencies:
+ '@vitest/pretty-format': 2.1.1
+ magic-string: 0.30.11
+ pathe: 1.1.2
+
'@vitest/spy@2.0.5':
dependencies:
tinyspy: 3.0.0
+ '@vitest/spy@2.1.1':
+ dependencies:
+ tinyspy: 3.0.0
+
'@vitest/utils@2.0.5':
dependencies:
'@vitest/pretty-format': 2.0.5
@@ -12807,6 +12917,12 @@ snapshots:
loupe: 3.1.1
tinyrainbow: 1.2.0
+ '@vitest/utils@2.1.1':
+ dependencies:
+ '@vitest/pretty-format': 2.1.1
+ loupe: 3.1.1
+ tinyrainbow: 1.2.0
+
'@volar/kit@2.4.0(typescript@5.5.4)':
dependencies:
'@volar/language-service': 2.4.0
@@ -16514,6 +16630,8 @@ snapshots:
tinybench@2.8.0: {}
+ tinybench@2.9.0: {}
+
tinyexec@0.3.0: {}
tinypool@1.0.0: {}
@@ -16806,6 +16924,23 @@ snapshots:
- supports-color
- terser
+ vite-node@2.1.1(@types/node@18.19.31)(sass@1.78.0):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.3.7
+ pathe: 1.1.2
+ vite: 5.4.3(@types/node@18.19.31)(sass@1.78.0)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
vite-plugin-inspect@0.8.7(rollup@4.21.2)(vite@5.4.3(@types/node@18.19.31)(sass@1.78.0)):
dependencies:
'@antfu/utils': 0.7.10
@@ -16923,6 +17058,41 @@ snapshots:
- supports-color
- terser
+ vitest@2.1.1(@types/node@18.19.31)(jsdom@23.2.0)(sass@1.78.0):
+ dependencies:
+ '@vitest/expect': 2.1.1
+ '@vitest/mocker': 2.1.1(vite@5.4.3(@types/node@18.19.31)(sass@1.78.0))
+ '@vitest/pretty-format': 2.1.1
+ '@vitest/runner': 2.1.1
+ '@vitest/snapshot': 2.1.1
+ '@vitest/spy': 2.1.1
+ '@vitest/utils': 2.1.1
+ chai: 5.1.1
+ debug: 4.3.7
+ magic-string: 0.30.11
+ pathe: 1.1.2
+ std-env: 3.7.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.0
+ tinypool: 1.0.0
+ tinyrainbow: 1.2.0
+ vite: 5.4.3(@types/node@18.19.31)(sass@1.78.0)
+ vite-node: 2.1.1(@types/node@18.19.31)(sass@1.78.0)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 18.19.31
+ jsdom: 23.2.0
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
volar-service-css@0.0.61(@volar/language-service@2.4.0):
dependencies:
vscode-css-languageservice: 6.3.0