Skip to content
Open
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/preload-redirect-cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: don't cache preloaded redirect results, so navigation re-runs `load` instead of replaying a stale redirect
7 changes: 5 additions & 2 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,11 @@ async function _preload_data(intent) {
token: preload,
promise: load_route({ ...intent, preload }).then((result) => {
preload_tokens.delete(preload);
if (result.type === 'loaded' && result.state.error) {
// Don't cache errors, because they might be transient
if (result.type === 'redirect' || (result.type === 'loaded' && result.state.error)) {
// Don't cache errors or redirects, because they might be transient.
// A cached redirect would be replayed without re-running `load`
// until a navigation commits, which can turn a resolvable
// redirect chain into a redirect loop
discard_load_cache();
}
return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { redirect } from '@sveltejs/kit';
import { state } from '../state.js';

export function load() {
if (!state.selected) {
redirect(303, '/data-sveltekit/preload-data/redirect-gate/select');
}
return {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>dashboard</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { redirect } from '@sveltejs/kit';
import { state } from '../state.js';

export function load() {
state.selected = true;
redirect(303, '/data-sveltekit/preload-data/redirect-gate/dashboard');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { state } from '../state.js';

export function load() {
// reset so the test can run repeatedly against the same server
state.selected = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<a
id="gated"
href="/data-sveltekit/preload-data/redirect-gate/dashboard"
data-sveltekit-preload-data="hover">go to dashboard</a
>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const state = { selected: false };
18 changes: 18 additions & 0 deletions packages/kit/test/apps/basics/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,24 @@ test.describe('data-sveltekit attributes', () => {
await expect(page).toHaveURL(offline_url);
});

test('preloaded redirect is not replayed on navigation', async ({ page }) => {
await page.goto('/data-sveltekit/preload-data/redirect-gate/start');

// preload /dashboard while its load redirects to /select
await page.locator('#gated').hover();
await page.locator('#gated').dispatchEvent('touchstart');
await Promise.all([
page.waitForTimeout(100), // wait for preloading to start
page.waitForLoadState('networkidle') // wait for preloading to finish
]);

// navigating must re-run load rather than replay the cached redirect,
// otherwise the mutual redirect never resolves and loops
await page.locator('#gated').click();
await expect(page.locator('h1')).toHaveText('dashboard');
await expect(page).toHaveURL(/redirect-gate\/dashboard/);
});

test('data-sveltekit-preload-data error does not block user navigation', async ({
page,
context,
Expand Down
Loading