Skip to content

Commit c51fb55

Browse files
authored
fix: respect page options when rendering an error page as a result of an error thrown from a load function on the server (#13695)
* fix * changeset * edit changeset * add test * use the page options for the nearest error page
1 parent 58508ca commit c51fb55

File tree

7 files changed

+42
-9
lines changed

7 files changed

+42
-9
lines changed

.changeset/khaki-queens-provide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: ensure that `ssr` and `csr` page options apply to error pages rendered as a result of a load function error on the server

packages/kit/src/runtime/server/page/index.js

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { render_response } from './render.js';
1515
import { respond_with_error } from './respond_with_error.js';
1616
import { get_data_json } from '../data/index.js';
1717
import { DEV } from 'esm-env';
18+
import { PageNodes } from '../../../utils/page_nodes.js';
1819

1920
/**
2021
* The maximum request depth permitted before assuming we're stuck in an infinite loop
@@ -93,10 +94,13 @@ export async function render_page(event, page, options, manifest, state, nodes,
9394
/** @type {import('./types.js').Fetched[]} */
9495
const fetched = [];
9596

97+
const ssr = nodes.ssr();
98+
const csr = nodes.csr();
99+
96100
// renders an empty 'shell' page if SSR is turned off and if there is
97101
// no server data to prerender. As a result, the load functions and rendering
98102
// only occur client-side.
99-
if (nodes.ssr() === false && !(state.prerendering && should_prerender_data)) {
103+
if (ssr === false && !(state.prerendering && should_prerender_data)) {
100104
// if the user makes a request through a non-enhanced form, the returned value is lost
101105
// because there is no SSR or client-side handling of the response
102106
if (DEV && action_result && !event.request.headers.has('x-sveltekit-action')) {
@@ -117,7 +121,7 @@ export async function render_page(event, page, options, manifest, state, nodes,
117121
fetched,
118122
page_config: {
119123
ssr: false,
120-
csr: nodes.csr()
124+
csr
121125
},
122126
status,
123127
error: null,
@@ -171,8 +175,6 @@ export async function render_page(event, page, options, manifest, state, nodes,
171175
});
172176
});
173177

174-
const csr = nodes.csr();
175-
176178
/** @type {Array<Promise<Record<string, any> | null>>} */
177179
const load_promises = nodes.data.map((node, i) => {
178180
if (load_error) throw load_error;
@@ -244,16 +246,22 @@ export async function render_page(event, page, options, manifest, state, nodes,
244246
let j = i;
245247
while (!branch[j]) j -= 1;
246248

249+
const layouts = compact(branch.slice(0, j + 1));
250+
const nodes = new PageNodes(layouts.map((layout) => layout.node));
251+
247252
return await render_response({
248253
event,
249254
options,
250255
manifest,
251256
state,
252257
resolve_opts,
253-
page_config: { ssr: true, csr: true },
258+
page_config: {
259+
ssr: nodes.ssr(),
260+
csr: nodes.csr()
261+
},
254262
status,
255263
error,
256-
branch: compact(branch.slice(0, j + 1)).concat({
264+
branch: layouts.concat({
257265
node,
258266
data: null,
259267
server_data: null
@@ -294,16 +302,14 @@ export async function render_page(event, page, options, manifest, state, nodes,
294302
});
295303
}
296304

297-
const ssr = nodes.ssr();
298-
299305
return await render_response({
300306
event,
301307
options,
302308
manifest,
303309
state,
304310
resolve_opts,
305311
page_config: {
306-
csr: nodes.csr(),
312+
csr,
307313
ssr
308314
},
309315
status,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script lang="ts">
2+
import { page } from '$app/stores';
3+
</script>
4+
5+
<h1>{$page.error.message}</h1>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// disables csr for the error page
2+
export const csr = false;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const csr = true;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function load() {
2+
throw new Error('Crashing now');
3+
}

packages/kit/test/apps/basics/test/server.test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,17 @@ test.describe('Errors', () => {
462462
});
463463
}
464464
});
465+
466+
test('error thrown from load on the server respects page options when rendering the error page', async ({
467+
request
468+
}) => {
469+
const res = await request.get('/errors/load-error-page-options/csr');
470+
expect(res.status()).toBe(500);
471+
const content = await res.text();
472+
expect(content).toContain('Crashing now');
473+
// the hydration script should not be present if the csr page option is respected
474+
expect(content).not.toContain('kit.start(app');
475+
});
465476
});
466477

467478
test.describe('Load', () => {

0 commit comments

Comments
 (0)