Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/orange-students-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

fix: render SPA shell when SSR is turned off and there is no server data
13 changes: 9 additions & 4 deletions packages/kit/src/runtime/server/page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// spa shell should still prererender when +page.server.js exists but it has no load function
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>this won't be prerendered</h1>
8 changes: 8 additions & 0 deletions packages/kit/test/prerendering/basics/test/tests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/<!doctype html>\n<html lang="en">([\s]*?)<head>([\s]*?)<meta charset="utf-8" \/>([\s]*?)<meta name="viewport" content="width=device-width, initial-scale=1" \/>([\s\S]*?)<\/head>\n([\s]*?)<body>([\s]*?)<script>([\s\S]*?)<\/script>([\s]*?)<\/body>\n<\/html>/g
);
});

test('inserts http-equiv tag for cache-control headers', () => {
const content = read('max-age.html');
expect(content).toMatch('<meta http-equiv="cache-control" content="max-age=300">');
Expand Down