Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: do not create unwanted record in history when redirecting after an invalidation #11895

Closed
Closed
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/spotty-lobsters-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

fix: redirect loop after invalidate
14 changes: 12 additions & 2 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,12 @@ async function _invalidate() {
if (!navigation_result || nav_token !== token) return;

if (navigation_result.type === 'redirect') {
return _goto(new URL(navigation_result.location, current.url).href, {}, 1, nav_token);
return _goto(
new URL(navigation_result.location, current.url).href,
{ replaceState: true },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is right. If the result is a redirect, we do want to create a history entry for the redirect. Can you can explain why you've made this change here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you don't want to create a history entry, because

  1. on server redirect (302) history entry is not created, and, IMO, client side and server side navigation should be consistent
  2. when you create history entry on client redirect, you create a loop in history. I mean, for example, if you press "go back" button in your browser, browser navigates to the "redirect" entry, which instantly goes forward again, so you essentially become stuck in a loop. With server redirects such loops cannot be achieved, and neither should they be achieved on the client side

Copy link
Member

@eltigerchino eltigerchino Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. So we want the intermediate navigations to not create history entries. Is that correct? But the final navigation should still create a history entry?

1,
nav_token
);
}

if (navigation_result.props.page) {
Expand Down Expand Up @@ -1336,7 +1341,12 @@ async function navigate({
route: { id: null }
});
} else {
_goto(new URL(navigation_result.location, url).href, {}, redirect_count + 1, nav_token);
_goto(
new URL(navigation_result.location, url).href,
{ replaceState: replace_state },
redirect_count + 1,
nav_token
);
return false;
}
} else if (/** @type {number} */ (navigation_result.props.page.status) >= 400) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export async function load({ cookies }) {
return {
loggedIn: cookies.get('logged_in') === '1'
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<h1>App with authorization</h1>
<a href="/redirect/app-with-auth/main" data-testid="enter"> enter </a>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { redirect } from '@sveltejs/kit';

export async function load({ parent }) {
const { loggedIn } = await parent();
if (!loggedIn) {
redirect(302, '/redirect/app-with-auth/signin');
}

return {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>main</h1>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { redirect } from '@sveltejs/kit';

export async function load({ parent }) {
const { loggedIn } = await parent();
if (loggedIn) {
redirect(302, '/redirect/app-with-auth/main');
}

return {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script>
import { invalidateAll } from '$app/navigation';

function login() {
document.cookie = 'logged_in=1;path=/redirect/app-with-auth';
invalidateAll();
}
</script>

<h1>signin</h1>
<button on:click={login} data-testid="login"> login </button>
15 changes: 15 additions & 0 deletions packages/kit/test/apps/basics/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,21 @@
expect(next_layout_2).toBe(next_layout_1);
expect(next_page_2).not.toBe(next_page_1);
});

test('does not create new records in history for intermediate redirects', async ({
page,
clicknav
}) => {
await page.goto('/redirect/app-with-auth');
await clicknav("a[data-testid='enter']");
expect(await page.textContent('h1')).toContain('signin');

await clicknav("button[data-testid='login']");
expect(await page.textContent('h1')).toContain('main');

await page.evaluate(() => window.history.back());
expect(await page.textContent('h1')).toContain('App with authorization');
});
});

test.describe('data-sveltekit attributes', () => {
Expand Down Expand Up @@ -954,7 +969,7 @@
expect(page.locator('p.loadingfail')).toBeHidden();
});

test('Catches fetch errors from server load functions (direct hit)', async ({ page }) => {

Check warning on line 972 in packages/kit/test/apps/basics/test/client.test.js

View workflow job for this annotation

GitHub Actions / test-kit (18, ubuntu-latest, chromium)

flaky test: Catches fetch errors from server load functions (direct hit)

retries: 2
page.goto('/streaming/server-error');
await expect(page.locator('p.eager')).toHaveText('eager');
await expect(page.locator('p.fail')).toHaveText('fail');
Expand Down
Loading