diff --git a/.changeset/lemon-bobcats-kick.md b/.changeset/lemon-bobcats-kick.md
new file mode 100644
index 000000000000..444863635afd
--- /dev/null
+++ b/.changeset/lemon-bobcats-kick.md
@@ -0,0 +1,5 @@
+---
+'astro': major
+---
+
+Default preview host to `localhost` instead of `127.0.0.1`. This allows the static server and integration preview servers to serve under ipv6.
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 7191f8488051..43f25171d500 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -155,8 +155,8 @@
"rehype": "^12.0.1",
"resolve": "^1.22.0",
"semver": "^7.3.7",
+ "server-destroy": "^1.0.1",
"shiki": "^0.11.1",
- "sirv": "^2.0.2",
"slash": "^4.0.0",
"string-width": "^5.1.2",
"strip-ansi": "^7.0.1",
@@ -171,7 +171,7 @@
"zod": "^3.17.3"
},
"devDependencies": {
- "@playwright/test": "^1.22.2",
+ "@playwright/test": "^1.29.2",
"@types/babel__generator": "^7.6.4",
"@types/babel__traverse": "^7.17.1",
"@types/chai": "^4.3.1",
@@ -191,6 +191,7 @@
"@types/resolve": "^1.20.2",
"@types/rimraf": "^3.0.2",
"@types/send": "^0.17.1",
+ "@types/server-destroy": "^1.0.1",
"@types/unist": "^2.0.6",
"astro-scripts": "workspace:*",
"chai": "^4.3.6",
diff --git a/packages/astro/src/core/dev/dev.ts b/packages/astro/src/core/dev/dev.ts
index 62c01ce78579..074501b04a34 100644
--- a/packages/astro/src/core/dev/dev.ts
+++ b/packages/astro/src/core/dev/dev.ts
@@ -49,9 +49,6 @@ export default async function dev(
// Start listening to the port
const devServerAddressInfo = await startContainer(restart.container);
- const site = settings.config.site
- ? new URL(settings.config.base, settings.config.site)
- : undefined;
info(
options.logging,
null,
@@ -59,7 +56,7 @@ export default async function dev(
startupTime: performance.now() - devStart,
resolvedUrls: restart.container.viteServer.resolvedUrls || { local: [], network: [] },
host: settings.config.server.host,
- site,
+ base: settings.config.base,
isRestart: options.isRestart,
})
);
diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts
index d46bf99916e3..817958876d7b 100644
--- a/packages/astro/src/core/messages.ts
+++ b/packages/astro/src/core/messages.ts
@@ -14,14 +14,11 @@ import {
underline,
yellow,
} from 'kleur/colors';
-import type { AddressInfo } from 'net';
-import os from 'os';
import { ResolvedServerUrls } from 'vite';
import { ZodError } from 'zod';
import { renderErrorMarkdown } from './errors/dev/utils.js';
import { AstroError, CompilerError, ErrorWithMetadata } from './errors/index.js';
-import { removeTrailingForwardSlash } from './path.js';
-import { emoji, getLocalAddress, padMultilineString } from './util.js';
+import { emoji, padMultilineString } from './util.js';
const PREFIX_PADDING = 6;
@@ -58,31 +55,26 @@ export function serverStart({
startupTime,
resolvedUrls,
host,
- site,
+ base,
isRestart = false,
}: {
startupTime: number;
resolvedUrls: ResolvedServerUrls;
host: string | boolean;
- site: URL | undefined;
+ base: string;
isRestart?: boolean;
}): string {
// PACKAGE_VERSION is injected at build-time
const version = process.env.PACKAGE_VERSION ?? '0.0.0';
- const rootPath = site ? site.pathname : '/';
const localPrefix = `${dim('┃')} Local `;
const networkPrefix = `${dim('┃')} Network `;
const emptyPrefix = ' '.repeat(11);
const localUrlMessages = resolvedUrls.local.map((url, i) => {
- return `${i === 0 ? localPrefix : emptyPrefix}${bold(
- cyan(removeTrailingForwardSlash(url) + rootPath)
- )}`;
+ return `${i === 0 ? localPrefix : emptyPrefix}${bold(cyan(new URL(url).origin + base))}`;
});
const networkUrlMessages = resolvedUrls.network.map((url, i) => {
- return `${i === 0 ? networkPrefix : emptyPrefix}${bold(
- cyan(removeTrailingForwardSlash(url) + rootPath)
- )}`;
+ return `${i === 0 ? networkPrefix : emptyPrefix}${bold(cyan(new URL(url).origin + base))}`;
});
if (networkUrlMessages.length === 0) {
@@ -109,50 +101,6 @@ export function serverStart({
.join('\n');
}
-export function resolveServerUrls({
- address,
- host,
- https,
-}: {
- address: AddressInfo;
- host: string | boolean;
- https: boolean;
-}): ResolvedServerUrls {
- const { address: networkAddress, port } = address;
- const localAddress = getLocalAddress(networkAddress, host);
- const networkLogging = getNetworkLogging(host);
- const toDisplayUrl = (hostname: string) => `${https ? 'https' : 'http'}://${hostname}:${port}`;
-
- let local = toDisplayUrl(localAddress);
- let network: string | null = null;
-
- if (networkLogging === 'visible') {
- const ipv4Networks = Object.values(os.networkInterfaces())
- .flatMap((networkInterface) => networkInterface ?? [])
- .filter(
- (networkInterface) =>
- networkInterface?.address &&
- // Node < v18
- ((typeof networkInterface.family === 'string' && networkInterface.family === 'IPv4') ||
- // Node >= v18
- (typeof networkInterface.family === 'number' && (networkInterface as any).family === 4))
- );
- for (let { address: ipv4Address } of ipv4Networks) {
- if (ipv4Address.includes('127.0.0.1')) {
- const displayAddress = ipv4Address.replace('127.0.0.1', localAddress);
- local = toDisplayUrl(displayAddress);
- } else {
- network = toDisplayUrl(ipv4Address);
- }
- }
- }
-
- return {
- local: [local],
- network: network ? [network] : [],
- };
-}
-
export function telemetryNotice() {
const headline = yellow(`Astro now collects ${bold('anonymous')} usage data.`);
const why = `This ${bold('optional program')} will help shape our roadmap.`;
@@ -228,11 +176,6 @@ export function cancelled(message: string, tip?: string) {
.join('\n');
}
-/** Display port in use */
-export function portInUse({ port }: { port: number }): string {
- return `Port ${port} in use. Trying a new one…`;
-}
-
const LOCAL_IP_HOSTS = new Set(['localhost', '127.0.0.1']);
export function getNetworkLogging(host: string | boolean): 'none' | 'host-to-expose' | 'visible' {
diff --git a/packages/astro/src/core/preview/index.ts b/packages/astro/src/core/preview/index.ts
index d4a5c8bb2cb5..4488e590387a 100644
--- a/packages/astro/src/core/preview/index.ts
+++ b/packages/astro/src/core/preview/index.ts
@@ -23,11 +23,9 @@ export default async function preview(
logging: logging,
});
await runHookConfigDone({ settings: settings, logging: logging });
- const host = getResolvedHostForHttpServer(settings.config.server.host);
- const { port, headers } = settings.config.server;
if (settings.config.output === 'static') {
- const server = await createStaticPreviewServer(settings, { logging, host, port, headers });
+ const server = await createStaticPreviewServer(settings, logging);
return server;
}
if (!settings.adapter) {
@@ -55,8 +53,8 @@ export default async function preview(
outDir: settings.config.outDir,
client: settings.config.build.client,
serverEntrypoint: new URL(settings.config.build.serverEntry, settings.config.build.server),
- host,
- port,
+ host: getResolvedHostForHttpServer(settings.config.server.host),
+ port: settings.config.server.port,
base: settings.config.base,
});
diff --git a/packages/astro/src/core/preview/static-preview-server.ts b/packages/astro/src/core/preview/static-preview-server.ts
index f74755aed550..8f5a88103920 100644
--- a/packages/astro/src/core/preview/static-preview-server.ts
+++ b/packages/astro/src/core/preview/static-preview-server.ts
@@ -1,15 +1,14 @@
-import type { AddressInfo } from 'net';
-import type { AstroSettings } from '../../@types/astro';
-import type { LogOptions } from '../logger/core';
-
-import fs from 'fs';
-import http, { OutgoingHttpHeaders } from 'http';
+import http from 'http';
import { performance } from 'perf_hooks';
-import sirv from 'sirv';
import { fileURLToPath } from 'url';
-import { notFoundTemplate, subpathNotUsedTemplate } from '../../template/4xx.js';
+import { preview, type PreviewServer as VitePreviewServer } from 'vite';
+import type { AstroSettings } from '../../@types/astro';
+import type { LogOptions } from '../logger/core';
import { error, info } from '../logger/core.js';
import * as msg from '../messages.js';
+import { getResolvedHostForHttpServer } from './util.js';
+import { vitePluginAstroPreview } from './vite-plugin-astro-preview.js';
+import enableDestroy from 'server-destroy';
export interface PreviewServer {
host?: string;
@@ -19,160 +18,65 @@ export interface PreviewServer {
stop(): Promise;
}
-const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/;
-
-/** The primary dev action */
export default async function createStaticPreviewServer(
settings: AstroSettings,
- {
- logging,
- host,
- port,
- headers,
- }: {
- logging: LogOptions;
- host: string | undefined;
- port: number;
- headers: OutgoingHttpHeaders | undefined;
- }
+ logging: LogOptions
): Promise {
const startServerTime = performance.now();
- const defaultOrigin = 'http://localhost';
- const trailingSlash = settings.config.trailingSlash;
- /** Base request URL. */
- let baseURL = new URL(settings.config.base, new URL(settings.config.site || '/', defaultOrigin));
- const staticFileServer = sirv(fileURLToPath(settings.config.outDir), {
- dev: true,
- etag: true,
- maxAge: 0,
- setHeaders: (res, pathname, stats) => {
- for (const [name, value] of Object.entries(headers ?? {})) {
- if (value) res.setHeader(name, value);
- }
- },
- });
- // Create the preview server, send static files out of the `dist/` directory.
- const server = http.createServer((req, res) => {
- const requestURL = new URL(req.url as string, defaultOrigin);
-
- // respond 404 to requests outside the base request directory
- if (!requestURL.pathname.startsWith(baseURL.pathname)) {
- res.statusCode = 404;
- res.end(subpathNotUsedTemplate(baseURL.pathname, requestURL.pathname));
- return;
- }
-
- /** Relative request path. */
- const pathname = requestURL.pathname.slice(baseURL.pathname.length - 1);
- const isRoot = pathname === '/';
- const hasTrailingSlash = isRoot || pathname.endsWith('/');
-
- function sendError(message: string) {
- res.statusCode = 404;
- res.end(notFoundTemplate(pathname, message));
- }
-
- switch (true) {
- case hasTrailingSlash && trailingSlash == 'never' && !isRoot:
- sendError('Not Found (trailingSlash is set to "never")');
- return;
- case !hasTrailingSlash &&
- trailingSlash == 'always' &&
- !isRoot &&
- !HAS_FILE_EXTENSION_REGEXP.test(pathname):
- sendError('Not Found (trailingSlash is set to "always")');
- return;
- default: {
- // HACK: rewrite req.url so that sirv finds the file
- req.url = '/' + req.url?.replace(baseURL.pathname, '');
- staticFileServer(req, res, () => {
- const errorPagePath = fileURLToPath(settings.config.outDir + '/404.html');
- if (fs.existsSync(errorPagePath)) {
- res.statusCode = 404;
- res.setHeader('Content-Type', 'text/html;charset=utf-8');
- res.end(fs.readFileSync(errorPagePath));
- } else {
- staticFileServer(req, res, () => {
- sendError('Not Found');
- });
- }
- });
- return;
- }
- }
- });
-
- let httpServer: http.Server;
-
- /** Expose dev server to `port` */
- function startServer(timerStart: number): Promise {
- let showedPortTakenMsg = false;
- let showedListenMsg = false;
- return new Promise((resolve, reject) => {
- const listen = () => {
- httpServer = server.listen(port, host, async () => {
- if (!showedListenMsg) {
- const resolvedUrls = msg.resolveServerUrls({
- address: server.address() as AddressInfo,
- host: settings.config.server.host,
- https: false,
- });
- info(
- logging,
- null,
- msg.serverStart({
- startupTime: performance.now() - timerStart,
- resolvedUrls,
- host: settings.config.server.host,
- site: baseURL,
- })
- );
- }
- showedListenMsg = true;
- resolve();
- });
- httpServer?.on('error', onError);
- };
-
- const onError = (err: NodeJS.ErrnoException) => {
- if (err.code && err.code === 'EADDRINUSE') {
- if (!showedPortTakenMsg) {
- info(logging, 'astro', msg.portInUse({ port }));
- showedPortTakenMsg = true; // only print this once
- }
- port++;
- return listen(); // retry
- } else {
- error(logging, 'astro', err.stack || err.message);
- httpServer?.removeListener('error', onError);
- reject(err); // reject
- }
- };
-
- listen();
+ let previewServer: VitePreviewServer;
+ try {
+ previewServer = await preview({
+ configFile: false,
+ base: settings.config.base,
+ appType: 'mpa',
+ build: {
+ outDir: fileURLToPath(settings.config.outDir),
+ },
+ preview: {
+ host: settings.config.server.host,
+ port: settings.config.server.port,
+ headers: settings.config.server.headers,
+ },
+ plugins: [vitePluginAstroPreview(settings)],
});
+ } catch (err) {
+ if (err instanceof Error) {
+ error(logging, 'astro', err.stack || err.message);
+ }
+ throw err;
}
- // Start listening on `hostname:port`.
- await startServer(startServerTime);
+ enableDestroy(previewServer.httpServer);
+
+ // Log server start URLs
+ info(
+ logging,
+ null,
+ msg.serverStart({
+ startupTime: performance.now() - startServerTime,
+ resolvedUrls: previewServer.resolvedUrls,
+ host: settings.config.server.host,
+ base: settings.config.base,
+ })
+ );
// Resolves once the server is closed
function closed() {
return new Promise((resolve, reject) => {
- httpServer!.addListener('close', resolve);
- httpServer!.addListener('error', reject);
+ previewServer.httpServer.addListener('close', resolve);
+ previewServer.httpServer.addListener('error', reject);
});
}
return {
- host,
- port,
+ host: getResolvedHostForHttpServer(settings.config.server.host),
+ port: settings.config.server.port,
closed,
- server: httpServer!,
+ server: previewServer.httpServer,
stop: async () => {
await new Promise((resolve, reject) => {
- httpServer.close((err) => (err ? reject(err) : resolve(undefined)));
+ previewServer.httpServer.destroy((err) => (err ? reject(err) : resolve(undefined)));
});
},
};
diff --git a/packages/astro/src/core/preview/util.ts b/packages/astro/src/core/preview/util.ts
index 556946d2bd32..d02e4c3c8a09 100644
--- a/packages/astro/src/core/preview/util.ts
+++ b/packages/astro/src/core/preview/util.ts
@@ -1,7 +1,7 @@
export function getResolvedHostForHttpServer(host: string | boolean) {
if (host === false) {
// Use a secure default
- return '127.0.0.1';
+ return 'localhost';
} else if (host === true) {
// If passed --host in the CLI without arguments
return undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)
@@ -9,3 +9,11 @@ export function getResolvedHostForHttpServer(host: string | boolean) {
return host;
}
}
+
+export function stripBase(path: string, base: string): string {
+ if (path === base) {
+ return '/';
+ }
+ const baseWithSlash = base.endsWith('/') ? base : base + '/';
+ return path.replace(RegExp('^' + baseWithSlash), '/');
+}
diff --git a/packages/astro/src/core/preview/vite-plugin-astro-preview.ts b/packages/astro/src/core/preview/vite-plugin-astro-preview.ts
new file mode 100644
index 000000000000..95ff4d225996
--- /dev/null
+++ b/packages/astro/src/core/preview/vite-plugin-astro-preview.ts
@@ -0,0 +1,68 @@
+import fs from 'fs';
+import { fileURLToPath } from 'url';
+import { Plugin } from 'vite';
+import { AstroSettings } from '../../@types/astro.js';
+import { notFoundTemplate, subpathNotUsedTemplate } from '../../template/4xx.js';
+import { stripBase } from './util.js';
+
+const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/;
+
+export function vitePluginAstroPreview(settings: AstroSettings): Plugin {
+ const { base, outDir, trailingSlash } = settings.config;
+
+ return {
+ name: 'astro:preview',
+ apply: 'serve',
+ configurePreviewServer(server) {
+ server.middlewares.use((req, res, next) => {
+ // respond 404 to requests outside the base request directory
+ if (!req.url!.startsWith(base)) {
+ res.statusCode = 404;
+ res.end(subpathNotUsedTemplate(base, req.url!));
+ return;
+ }
+
+ const pathname = stripBase(req.url!, base);
+ const isRoot = pathname === '/';
+
+ // Validate trailingSlash
+ if (!isRoot) {
+ const hasTrailingSlash = pathname.endsWith('/');
+
+ if (hasTrailingSlash && trailingSlash == 'never') {
+ res.statusCode = 404;
+ res.end(notFoundTemplate(pathname, 'Not Found (trailingSlash is set to "never")'));
+ return;
+ }
+
+ if (
+ !hasTrailingSlash &&
+ trailingSlash == 'always' &&
+ !HAS_FILE_EXTENSION_REGEXP.test(pathname)
+ ) {
+ res.statusCode = 404;
+ res.end(notFoundTemplate(pathname, 'Not Found (trailingSlash is set to "always")'));
+ return;
+ }
+ }
+
+ next();
+ });
+
+ return () => {
+ server.middlewares.use((req, res) => {
+ const errorPagePath = fileURLToPath(outDir + '/404.html');
+ if (fs.existsSync(errorPagePath)) {
+ res.statusCode = 404;
+ res.setHeader('Content-Type', 'text/html;charset=utf-8');
+ res.end(fs.readFileSync(errorPagePath));
+ } else {
+ const pathname = stripBase(req.url!, base);
+ res.statusCode = 404;
+ res.end(notFoundTemplate(pathname, 'Not Found'));
+ }
+ });
+ };
+ },
+ };
+}
diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts
index d6f95062a958..79148797b5ae 100644
--- a/packages/astro/src/core/util.ts
+++ b/packages/astro/src/core/util.ts
@@ -164,14 +164,6 @@ export function emoji(char: string, fallback: string) {
return process.platform !== 'win32' ? char : fallback;
}
-export function getLocalAddress(serverAddress: string, host: string | boolean): string {
- if (typeof host === 'boolean' || host === 'localhost') {
- return 'localhost';
- } else {
- return serverAddress;
- }
-}
-
/**
* Simulate Vite's resolve and import analysis so we can import the id as an URL
* through a script tag or a dynamic import as-is.
diff --git a/packages/astro/test/cli.test.js b/packages/astro/test/cli.test.js
index fb5d54d38fa8..2c1dd0dead9d 100644
--- a/packages/astro/test/cli.test.js
+++ b/packages/astro/test/cli.test.js
@@ -77,17 +77,11 @@ describe('astro cli', () => {
const localURL = new URL(local);
const networkURL = new URL(network);
- if (cmd === 'dev') {
- expect(localURL.hostname).to.be.oneOf(
- ['localhost', '127.0.0.1'],
- `Expected local URL to be on localhost`
- );
- } else {
- expect(localURL.hostname).to.be.equal(
- flagValue ?? 'localhost',
- `Expected local URL to be on localhost`
- );
- }
+ expect(localURL.hostname).to.be.oneOf(
+ ['localhost', '127.0.0.1'],
+ `Expected local URL to be on localhost`
+ );
+
// Note: our tests run in parallel so this could be 3000+!
expect(Number.parseInt(localURL.port)).to.be.greaterThanOrEqual(
3000,
@@ -113,17 +107,11 @@ describe('astro cli', () => {
expect(network).to.not.be.undefined;
const localURL = new URL(local);
- if (cmd === 'dev') {
- expect(localURL.hostname).to.be.oneOf(
- ['localhost', '127.0.0.1'],
- `Expected local URL to be on localhost`
- );
- } else {
- expect(localURL.hostname).to.be.equal(
- 'localhost',
- `Expected local URL to be on localhost`
- );
- }
+ expect(localURL.hostname).to.be.oneOf(
+ ['localhost', '127.0.0.1'],
+ `Expected local URL to be on localhost`
+ );
+
expect(() => new URL(networkURL)).to.throw();
});
});
@@ -140,14 +128,10 @@ describe('astro cli', () => {
expect(network).to.be.undefined;
const localURL = new URL(local);
- if (cmd === 'dev') {
- expect(localURL.hostname).to.be.oneOf(
- ['localhost', '127.0.0.1'],
- `Expected local URL to be on localhost`
- );
- } else {
- expect(localURL.hostname).to.be.equal(flagValue, `Expected local URL to be on localhost`);
- }
+ expect(localURL.hostname).to.be.oneOf(
+ ['localhost', '127.0.0.1'],
+ `Expected local URL to be on localhost`
+ );
});
});
});
diff --git a/packages/integrations/prefetch/package.json b/packages/integrations/prefetch/package.json
index 11f9bdc8ea00..414bd2c33697 100644
--- a/packages/integrations/prefetch/package.json
+++ b/packages/integrations/prefetch/package.json
@@ -31,13 +31,13 @@
"test:match": "playwright test -g"
},
"devDependencies": {
- "@playwright/test": "^1.26.0",
+ "@playwright/test": "^1.29.2",
"@types/chai": "^4.3.1",
"@types/chai-as-promised": "^7.1.5",
"@types/mocha": "^9.1.1",
"astro": "workspace:*",
"astro-scripts": "workspace:*",
- "playwright": "^1.22.2"
+ "playwright": "^1.29.2"
},
"dependencies": {
"throttles": "^1.0.1"
diff --git a/packages/integrations/prefetch/test/basic-prefetch.test.js b/packages/integrations/prefetch/test/basic-prefetch.test.js
index 576bd19bd2e3..6bab8a478d08 100644
--- a/packages/integrations/prefetch/test/basic-prefetch.test.js
+++ b/packages/integrations/prefetch/test/basic-prefetch.test.js
@@ -19,7 +19,7 @@ test.describe('Basic prefetch', () => {
test('skips /admin', async ({ page, astro }) => {
const requests = [];
- page.on('request', async (request) => requests.push(request.url()));
+ page.on('request', (request) => requests.push(request.url()));
await page.goto(astro.resolveUrl('/'));
@@ -56,7 +56,7 @@ test.describe('Basic prefetch', () => {
test('skips /admin', async ({ page, astro }) => {
const requests = [];
- page.on('request', async (request) => requests.push(request.url()));
+ page.on('request', (request) => requests.push(request.url()));
await page.goto(astro.resolveUrl('/'));
diff --git a/packages/integrations/prefetch/test/custom-selectors.test.js b/packages/integrations/prefetch/test/custom-selectors.test.js
index d57ac3b908cb..803e1dc3b401 100644
--- a/packages/integrations/prefetch/test/custom-selectors.test.js
+++ b/packages/integrations/prefetch/test/custom-selectors.test.js
@@ -27,7 +27,7 @@ test.describe('Custom prefetch selectors', () => {
test('only prefetches /contact', async ({ page, astro }) => {
const requests = [];
- page.on('request', async (request) => requests.push(request.url()));
+ page.on('request', (request) => requests.push(request.url()));
await page.goto(astro.resolveUrl('/'));
@@ -64,7 +64,7 @@ test.describe('Custom prefetch selectors', () => {
test('only prefetches /contact', async ({ page, astro }) => {
const requests = [];
- page.on('request', async (request) => requests.push(request.url()));
+ page.on('request', (request) => requests.push(request.url()));
await page.goto(astro.resolveUrl('/'));
diff --git a/packages/integrations/prefetch/test/style-prefetch.test.js b/packages/integrations/prefetch/test/style-prefetch.test.js
index 8e89a35e336a..b9bb0b04369a 100644
--- a/packages/integrations/prefetch/test/style-prefetch.test.js
+++ b/packages/integrations/prefetch/test/style-prefetch.test.js
@@ -39,7 +39,7 @@ test.describe('Style prefetch', () => {
test('style fetching', async ({ page, astro }) => {
const requests = [];
- page.on('request', async (request) => requests.push(request.url()));
+ page.on('request', (request) => requests.push(request.url()));
await page.goto(astro.resolveUrl('/'));
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 85466367163f..6434adaf6f79 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -396,7 +396,7 @@ importers:
'@babel/plugin-transform-react-jsx': ^7.17.12
'@babel/traverse': ^7.18.2
'@babel/types': ^7.18.4
- '@playwright/test': ^1.22.2
+ '@playwright/test': ^1.29.2
'@types/babel__core': ^7.1.19
'@types/babel__generator': ^7.6.4
'@types/babel__traverse': ^7.17.1
@@ -418,6 +418,7 @@ importers:
'@types/resolve': ^1.20.2
'@types/rimraf': ^3.0.2
'@types/send': ^0.17.1
+ '@types/server-destroy': ^1.0.1
'@types/unist': ^2.0.6
'@types/yargs-parser': ^21.0.0
acorn: ^8.8.1
@@ -466,8 +467,8 @@ importers:
rollup: ^3.9.0
sass: ^1.52.2
semver: ^7.3.7
+ server-destroy: ^1.0.1
shiki: ^0.11.1
- sirv: ^2.0.2
slash: ^4.0.0
srcset-parse: ^1.1.0
string-width: ^5.1.2
@@ -529,8 +530,8 @@ importers:
rehype: 12.0.1
resolve: 1.22.1
semver: 7.3.8
+ server-destroy: 1.0.1
shiki: 0.11.1
- sirv: 2.0.2
slash: 4.0.0
string-width: 5.1.2
strip-ansi: 7.0.1
@@ -564,6 +565,7 @@ importers:
'@types/resolve': 1.20.2
'@types/rimraf': 3.0.2
'@types/send': 0.17.1
+ '@types/server-destroy': 1.0.1
'@types/unist': 2.0.6
astro-scripts: link:../../scripts
chai: 4.3.7
@@ -3139,13 +3141,13 @@ importers:
packages/integrations/prefetch:
specifiers:
- '@playwright/test': ^1.26.0
+ '@playwright/test': ^1.29.2
'@types/chai': ^4.3.1
'@types/chai-as-promised': ^7.1.5
'@types/mocha': ^9.1.1
astro: workspace:*
astro-scripts: workspace:*
- playwright: ^1.22.2
+ playwright: ^1.29.2
throttles: ^1.0.1
dependencies:
throttles: 1.0.1
@@ -7055,6 +7057,7 @@ packages:
/@types/node/14.18.36:
resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==}
+ dev: true
/@types/node/16.18.11:
resolution: {integrity: sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==}
@@ -7126,7 +7129,7 @@ packages:
/@types/resolve/1.17.1:
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
dependencies:
- '@types/node': 14.18.36
+ '@types/node': 18.11.18
/@types/resolve/1.20.2:
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
@@ -7141,7 +7144,7 @@ packages:
/@types/sax/1.2.4:
resolution: {integrity: sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==}
dependencies:
- '@types/node': 17.0.45
+ '@types/node': 18.11.18
dev: false
/@types/scheduler/0.16.2:
@@ -7162,6 +7165,12 @@ packages:
'@types/node': 18.11.18
dev: true
+ /@types/server-destroy/1.0.1:
+ resolution: {integrity: sha512-77QGr7waZbE0Y0uF+G+uH3H3SmhyA78Jf2r5r7QSrpg0U3kSXduWpGjzP9PvPLR/KCy+kHjjpnugRHsYTnHopg==}
+ dependencies:
+ '@types/node': 18.11.18
+ dev: true
+
/@types/set-cookie-parser/2.4.2:
resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==}
dependencies:
@@ -11129,7 +11138,7 @@ packages:
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
engines: {node: '>= 10.13.0'}
dependencies:
- '@types/node': 14.18.36
+ '@types/node': 18.11.18
merge-stream: 2.0.0
supports-color: 7.2.0
@@ -13994,6 +14003,10 @@ packages:
randombytes: 2.1.0
dev: true
+ /server-destroy/1.0.1:
+ resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==}
+ dev: false
+
/set-blocking/2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}