diff --git a/.changeset/preview-base-trailing-slash-redirect.md b/.changeset/preview-base-trailing-slash-redirect.md new file mode 100644 index 000000000000..0542629ed4f5 --- /dev/null +++ b/.changeset/preview-base-trailing-slash-redirect.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: preserve `paths.base` when `vite preview` redirects a prerendered page to the correct trailing slash diff --git a/packages/kit/src/exports/vite/preview/index.js b/packages/kit/src/exports/vite/preview/index.js index c16b7ef2e8cf..16dc18c45dbd 100644 --- a/packages/kit/src/exports/vite/preview/index.js +++ b/packages/kit/src/exports/vite/preview/index.js @@ -9,6 +9,7 @@ import sirv from 'sirv'; import { loadEnv, normalizePath } from 'vite'; import { createReadableStream, getRequest, setResponse } from '../../../exports/node/index.js'; import { SVELTE_KIT_ASSETS } from '../../../constants.js'; +import { relative_pathname } from '../../../utils/url.js'; import { is_chrome_devtools_request, not_found } from '../utils.js'; import { stackless } from '../../../utils/error.js'; @@ -176,9 +177,9 @@ export async function preview(vite, vite_config, svelte_config) { } if (redirect) { - if (search) redirect += search; - res.writeHead(307, { - location: redirect + res.writeHead(308, { + // relative so (possibly invisible) path prefixes are preserved + location: relative_pathname(pathname, redirect) + search }); res.end(); diff --git a/packages/kit/test/apps/options-2/test/test.js b/packages/kit/test/apps/options-2/test/test.js index 21ab3a7a1fd5..b39253268b25 100644 --- a/packages/kit/test/apps/options-2/test/test.js +++ b/packages/kit/test/apps/options-2/test/test.js @@ -129,6 +129,19 @@ test.describe('trailing slash', () => { await clicknav('a[href="/basepath/trailing-slash-server/prerender"]'); await expect(page.locator('h2')).toHaveText('/basepath/trailing-slash-server/prerender/'); }); + + test('normalizes the trailing slash of a prerendered page without dropping the base', async ({ + request + }) => { + const response = await request.get('/basepath/trailing-slash-server/prerender'); + expect(new URL(response.url()).pathname).toBe('/basepath/trailing-slash-server/prerender/'); + expect(response.status()).toBe(200); + + const redirect = await request.get('/basepath/trailing-slash-server/prerender', { + maxRedirects: 0 + }); + expect(redirect.status()).toBe(308); + }); }); test.describe('Service worker', () => {