diff --git a/.changeset/gold-meals-listen.md b/.changeset/gold-meals-listen.md new file mode 100644 index 000000000000..473ae31669a8 --- /dev/null +++ b/.changeset/gold-meals-listen.md @@ -0,0 +1,7 @@ +--- +'@sveltejs/adapter-cloudflare-workers': patch +'@sveltejs/adapter-cloudflare': patch +'@sveltejs/kit': patch +--- + +fix: retain URL query string for trailing slash redirects to prerendered pages diff --git a/packages/adapter-cloudflare-workers/files/entry.js b/packages/adapter-cloudflare-workers/files/entry.js index a9960b4b2e12..3e4f2075c2fd 100644 --- a/packages/adapter-cloudflare-workers/files/entry.js +++ b/packages/adapter-cloudflare-workers/files/entry.js @@ -40,7 +40,7 @@ export default { }); } - let { pathname } = url; + let { pathname, search } = url; try { pathname = decodeURIComponent(pathname); } catch { @@ -57,7 +57,7 @@ export default { manifest.assets.has(filename) || manifest.assets.has(filename + '/index.html'); } - const location = pathname.at(-1) === '/' ? stripped_pathname : pathname + '/'; + let location = pathname.at(-1) === '/' ? stripped_pathname : pathname + '/'; if (is_static_asset || prerendered.has(pathname)) { return get_asset_from_kv(req, env, context, (request, options) => { @@ -69,6 +69,7 @@ export default { return mapRequestToAsset(request, options); }); } else if (location && prerendered.has(location)) { + if (search) location += search; return new Response('', { status: 308, headers: { diff --git a/packages/adapter-cloudflare/src/worker.js b/packages/adapter-cloudflare/src/worker.js index 59e6af9f54a3..ac0378536c34 100644 --- a/packages/adapter-cloudflare/src/worker.js +++ b/packages/adapter-cloudflare/src/worker.js @@ -14,7 +14,7 @@ const worker = { let res = !pragma.includes('no-cache') && (await Cache.lookup(req)); if (res) return res; - let { pathname } = new URL(req.url); + let { pathname, search } = new URL(req.url); try { pathname = decodeURIComponent(pathname); } catch { @@ -31,11 +31,12 @@ const worker = { manifest.assets.has(filename) || manifest.assets.has(filename + '/index.html'); } - const location = pathname.at(-1) === '/' ? stripped_pathname : pathname + '/'; + let location = pathname.at(-1) === '/' ? stripped_pathname : pathname + '/'; if (is_static_asset || prerendered.has(pathname)) { res = await env.ASSETS.fetch(req); } else if (location && prerendered.has(location)) { + if (search) location += search; res = new Response('', { status: 308, headers: { diff --git a/packages/kit/src/exports/vite/preview/index.js b/packages/kit/src/exports/vite/preview/index.js index b6a849093909..77ac50745158 100644 --- a/packages/kit/src/exports/vite/preview/index.js +++ b/packages/kit/src/exports/vite/preview/index.js @@ -102,7 +102,7 @@ export async function preview(vite, vite_config, svelte_config) { return; } - const { pathname } = new URL(/** @type {string} */ (req.url), 'http://dummy'); + const { pathname, search } = new URL(/** @type {string} */ (req.url), 'http://dummy'); let filename = normalizePath( join(svelte_config.kit.outDir, 'output/prerendered/pages' + pathname) @@ -113,6 +113,7 @@ export async function preview(vite, vite_config, svelte_config) { const has_trailing_slash = pathname.endsWith('/'); const html_filename = `${filename}${has_trailing_slash ? 'index.html' : '.html'}`; + /** @type {string | undefined} */ let redirect; if (is_file(html_filename)) { @@ -127,6 +128,7 @@ export async function preview(vite, vite_config, svelte_config) { } if (redirect) { + if (search) redirect += search; res.writeHead(307, { location: redirect }); diff --git a/packages/kit/test/apps/basics/src/routes/routing/prerendered/+layout.js b/packages/kit/test/apps/basics/src/routes/routing/prerendered/+layout.js new file mode 100644 index 000000000000..189f71e2e1b3 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/routing/prerendered/+layout.js @@ -0,0 +1 @@ +export const prerender = true; diff --git a/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/always/+page.js b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/always/+page.js new file mode 100644 index 000000000000..d3c325085ed2 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/always/+page.js @@ -0,0 +1 @@ +export const trailingSlash = 'always'; diff --git a/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/always/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/always/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/ignore/+page.js b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/ignore/+page.js new file mode 100644 index 000000000000..42a828c116a3 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/ignore/+page.js @@ -0,0 +1 @@ +export const trailingSlash = 'ignore'; diff --git a/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/ignore/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/ignore/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/never/+page.svelte b/packages/kit/test/apps/basics/src/routes/routing/prerendered/trailing-slash/never/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/test/apps/basics/svelte.config.js b/packages/kit/test/apps/basics/svelte.config.js index fa9ea301b9a1..b74fb4612ff7 100644 --- a/packages/kit/test/apps/basics/svelte.config.js +++ b/packages/kit/test/apps/basics/svelte.config.js @@ -2,6 +2,12 @@ const config = { kit: { prerender: { + entries: [ + '*', + '/routing/prerendered/trailing-slash/always/', + '/routing/prerendered/trailing-slash/never', + '/routing/prerendered/trailing-slash/ignore' + ], handleHttpError: 'warn' }, diff --git a/packages/kit/test/apps/basics/test/server.test.js b/packages/kit/test/apps/basics/test/server.test.js index 8e06f85062ed..50f1d47341e0 100644 --- a/packages/kit/test/apps/basics/test/server.test.js +++ b/packages/kit/test/apps/basics/test/server.test.js @@ -502,6 +502,21 @@ test.describe('Routing', () => { const data = await response.json(); expect(data).toEqual({ surprise: 'lol' }); }); + + test('Vite trailing slash redirect for prerendered pages retains URL query string', async ({ + request + }) => { + if (process.env.DEV) return; + + let response = await request.get('/routing/prerendered/trailing-slash/always?a=1'); + expect(new URL(response.url()).search).toBe('?a=1'); + + response = await request.get('/routing/prerendered/trailing-slash/never/?a=1'); + expect(new URL(response.url()).search).toBe('?a=1'); + + response = await request.get('/routing/prerendered/trailing-slash/ignore/?a=1'); + expect(new URL(response.url()).search).toBe('?a=1'); + }); }); test.describe('Shadowed pages', () => {