Skip to content

Commit

Permalink
fix: handle redirect thrown from root layout load when client-side na…
Browse files Browse the repository at this point in the history
…vigating 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.
  • Loading branch information
eltigerchino authored Jan 13, 2025
1 parent 5b667e4 commit d4bcfcc
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-schools-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

fix: handle `Redirect` thrown from root layout load function when client-side navigating to a non-existent page
57 changes: 33 additions & 24 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -1153,32 +1153,41 @@ async function load_root_error_page({ status, error, url, route }) {
}
}

const root_layout = await load_node({
loader: default_layout_loader,
url,
params,
route,
parent: () => Promise.resolve({}),
server_data_node: create_data_node(server_data_node)
});
try {
const root_layout = await load_node({
loader: default_layout_loader,
url,
params,
route,
parent: () => Promise.resolve({}),
server_data_node: create_data_node(server_data_node)
});

/** @type {import('./types.js').BranchNode} */
const root_error = {
node: await default_error_loader(),
loader: default_error_loader,
universal: null,
server: null,
data: null
};
/** @type {import('./types.js').BranchNode} */
const root_error = {
node: await default_error_loader(),
loader: default_error_loader,
universal: null,
server: null,
data: null
};

return get_navigation_result_from_branch({
url,
params,
branch: [root_layout, root_error],
status,
error,
route: null
});
return get_navigation_result_from_branch({
url,
params,
branch: [root_layout, root_error],
status,
error,
route: null
});
} catch (error) {
if (error instanceof Redirect) {
return _goto(new URL(error.location, location.href), {}, 0);
}

// TODO: this falls back to the server when a server exists, but what about SPA mode?
throw error;
}
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/kit/test/apps/no-ssr/src/routes/+layout.js
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
import { redirect } from '@sveltejs/kit';

export const ssr = false;

export const load = ({ url }) => {
if (url.pathname === '/redirect') {
redirect(302, '/');
}
};
1 change: 1 addition & 0 deletions packages/kit/test/apps/no-ssr/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>home</h1>
9 changes: 7 additions & 2 deletions packages/kit/test/apps/no-ssr/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ test.skip(({ javaScriptEnabled }) => !javaScriptEnabled);
test.describe.configure({ mode: 'parallel' });

test('navigating to a non-existent route renders the default error page', async ({ page }) => {
test.setTimeout(3000);
await page.goto('/non-existent-route');
await page.waitForLoadState('networkidle');
expect(await page.textContent('h1')).toBe('404');
});

test('navigating to a non-existent route redirects if redirect in the root layout', async ({
page
}) => {
await page.goto('/redirect');
expect(await page.textContent('h1')).toBe('home');
});

0 comments on commit d4bcfcc

Please sign in to comment.