diff --git a/.changeset/orange-students-hide.md b/.changeset/orange-students-hide.md new file mode 100644 index 000000000000..92606c701020 --- /dev/null +++ b/.changeset/orange-students-hide.md @@ -0,0 +1,5 @@ +--- +"@sveltejs/kit": patch +--- + +fix: render SPA shell when SSR is turned off and there is no server data diff --git a/packages/kit/src/runtime/server/page/index.js b/packages/kit/src/runtime/server/page/index.js index 067d60585cd9..f8878e112328 100644 --- a/packages/kit/src/runtime/server/page/index.js +++ b/packages/kit/src/runtime/server/page/index.js @@ -72,7 +72,7 @@ export async function render_page(event, page, options, manifest, state, resolve } } - const should_prerender_data = nodes.some((node) => node?.server); + const should_prerender_data = nodes.some((node) => node?.server?.load); const data_pathname = add_data_suffix(event.url.pathname); // it's crucial that we do this before returning the non-SSR response, otherwise @@ -98,7 +98,10 @@ export async function render_page(event, page, options, manifest, state, resolve /** @type {import('./types.js').Fetched[]} */ const fetched = []; - if (get_option(nodes, 'ssr') === false && !state.prerendering) { + // renders an empty 'shell' page if SSR is turned off and if there is + // no server data to prerender. As a result, the load functions and rendering + // only occur client-side. + if (get_option(nodes, 'ssr') === false && !(state.prerendering && should_prerender_data)) { return await render_response({ branch: [], fetched, @@ -281,6 +284,8 @@ export async function render_page(event, page, options, manifest, state, resolve }); } + const ssr = get_option(nodes, 'ssr') ?? true; + return await render_response({ event, options, @@ -289,11 +294,11 @@ export async function render_page(event, page, options, manifest, state, resolve resolve_opts, page_config: { csr: get_option(nodes, 'csr') ?? true, - ssr: get_option(nodes, 'ssr') ?? true + ssr }, status, error: null, - branch: compact(branch), + branch: ssr === false ? [] : compact(branch), action_result, fetched }); diff --git a/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.js b/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.js new file mode 100644 index 000000000000..55a527fff567 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.js @@ -0,0 +1,10 @@ +import { redirect } from '@sveltejs/kit'; + +export const prerender = true; + +export const ssr = false; + +/** @type {import('@sveltejs/kit').Load} */ +export function load() { + redirect(301, 'https://example.com/redirected'); +} diff --git a/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.server.js b/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.server.js new file mode 100644 index 000000000000..7dbe1c850533 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.server.js @@ -0,0 +1 @@ +// spa shell should still prererender when +page.server.js exists but it has no load function diff --git a/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.svelte b/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.svelte new file mode 100644 index 000000000000..c1c9cf988847 --- /dev/null +++ b/packages/kit/test/prerendering/basics/src/routes/spa-shell/+page.svelte @@ -0,0 +1 @@ +

this won't be prerendered

diff --git a/packages/kit/test/prerendering/basics/test/tests.spec.js b/packages/kit/test/prerendering/basics/test/tests.spec.js index ecf337c35a76..04bb754ef70f 100644 --- a/packages/kit/test/prerendering/basics/test/tests.spec.js +++ b/packages/kit/test/prerendering/basics/test/tests.spec.js @@ -60,6 +60,14 @@ test('renders a relative redirect', () => { ); }); +test('renders a shell when SSR is turned off and there is no server data', () => { + const content = read('spa-shell.html'); + assert.match( + content, + /\n([\s]*?)([\s]*?)([\s]*?)([\s\S]*?)<\/head>\n([\s]*?)([\s]*?)