Skip to content

Commit d4bcfcc

Browse files
authoredJan 13, 2025··
fix: handle redirect thrown from root layout load when client-side navigating to a non-existent page (#12005)
fixes #11099 We end up in that code path when encountering a 404 route, because we first try to fall back to the server, and load the root error page else, at which point the layout load is run.
1 parent 5b667e4 commit d4bcfcc

File tree

5 files changed

+54
-26
lines changed

5 files changed

+54
-26
lines changed
 

‎.changeset/silver-schools-battle.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@sveltejs/kit": patch
3+
---
4+
5+
fix: handle `Redirect` thrown from root layout load function when client-side navigating to a non-existent page

‎packages/kit/src/runtime/client/client.js

+33-24
Original file line numberDiff line numberDiff line change
@@ -1153,32 +1153,41 @@ async function load_root_error_page({ status, error, url, route }) {
11531153
}
11541154
}
11551155

1156-
const root_layout = await load_node({
1157-
loader: default_layout_loader,
1158-
url,
1159-
params,
1160-
route,
1161-
parent: () => Promise.resolve({}),
1162-
server_data_node: create_data_node(server_data_node)
1163-
});
1156+
try {
1157+
const root_layout = await load_node({
1158+
loader: default_layout_loader,
1159+
url,
1160+
params,
1161+
route,
1162+
parent: () => Promise.resolve({}),
1163+
server_data_node: create_data_node(server_data_node)
1164+
});
11641165

1165-
/** @type {import('./types.js').BranchNode} */
1166-
const root_error = {
1167-
node: await default_error_loader(),
1168-
loader: default_error_loader,
1169-
universal: null,
1170-
server: null,
1171-
data: null
1172-
};
1166+
/** @type {import('./types.js').BranchNode} */
1167+
const root_error = {
1168+
node: await default_error_loader(),
1169+
loader: default_error_loader,
1170+
universal: null,
1171+
server: null,
1172+
data: null
1173+
};
11731174

1174-
return get_navigation_result_from_branch({
1175-
url,
1176-
params,
1177-
branch: [root_layout, root_error],
1178-
status,
1179-
error,
1180-
route: null
1181-
});
1175+
return get_navigation_result_from_branch({
1176+
url,
1177+
params,
1178+
branch: [root_layout, root_error],
1179+
status,
1180+
error,
1181+
route: null
1182+
});
1183+
} catch (error) {
1184+
if (error instanceof Redirect) {
1185+
return _goto(new URL(error.location, location.href), {}, 0);
1186+
}
1187+
1188+
// TODO: this falls back to the server when a server exists, but what about SPA mode?
1189+
throw error;
1190+
}
11821191
}
11831192

11841193
/**
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1+
import { redirect } from '@sveltejs/kit';
2+
13
export const ssr = false;
4+
5+
export const load = ({ url }) => {
6+
if (url.pathname === '/redirect') {
7+
redirect(302, '/');
8+
}
9+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<h1>home</h1>

‎packages/kit/test/apps/no-ssr/test/test.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ test.skip(({ javaScriptEnabled }) => !javaScriptEnabled);
88
test.describe.configure({ mode: 'parallel' });
99

1010
test('navigating to a non-existent route renders the default error page', async ({ page }) => {
11-
test.setTimeout(3000);
1211
await page.goto('/non-existent-route');
13-
await page.waitForLoadState('networkidle');
1412
expect(await page.textContent('h1')).toBe('404');
1513
});
14+
15+
test('navigating to a non-existent route redirects if redirect in the root layout', async ({
16+
page
17+
}) => {
18+
await page.goto('/redirect');
19+
expect(await page.textContent('h1')).toBe('home');
20+
});

0 commit comments

Comments
 (0)
Please sign in to comment.