From c78aa26fbf46edf7bb09a5d87ded528e91bf7966 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 22 Jun 2025 20:41:40 -0700 Subject: [PATCH 1/5] fix: prevent infinite loop when calling `pushState`/`replaceState` in effect --- .changeset/chatty-pears-notice.md | 5 +++++ packages/kit/src/runtime/client/client.js | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changeset/chatty-pears-notice.md diff --git a/.changeset/chatty-pears-notice.md b/.changeset/chatty-pears-notice.md new file mode 100644 index 000000000000..ec58e64f6435 --- /dev/null +++ b/.changeset/chatty-pears-notice.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +fix: prevent infinite loop when calling `pushState`/`replaceState` in effect diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 4b8eb5831e4a..e371c92f2da9 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -39,6 +39,7 @@ import { HttpError, Redirect, SvelteKitError } from '../control.js'; import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM, validate_depends } from '../shared.js'; import { get_message, get_status } from '../../utils/error.js'; import { writable } from 'svelte/store'; +import { untrack } from 'svelte'; import { page, update, navigating } from './state.svelte.js'; import { add_data_suffix, add_resolution_suffix } from '../pathname.js'; @@ -2111,7 +2112,7 @@ export function pushState(url, state) { page.state = state; root.$set({ // we need to assign a new page object so that subscribers are correctly notified - page: clone_page(page) + page: untrack(() => clone_page(page)) }); clear_onward_history(current_history_index, current_navigation_index); @@ -2154,7 +2155,7 @@ export function replaceState(url, state) { page.state = state; root.$set({ - page: clone_page(page) + page: untrack(() => clone_page(page)) }); } From 273fe09d788909e55d798f4f097d3f0dc2ef7958 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 22 Jun 2025 20:43:58 -0700 Subject: [PATCH 2/5] oops --- .changeset/chatty-pears-notice.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/chatty-pears-notice.md b/.changeset/chatty-pears-notice.md index ec58e64f6435..6f811b8da9e5 100644 --- a/.changeset/chatty-pears-notice.md +++ b/.changeset/chatty-pears-notice.md @@ -1,5 +1,5 @@ --- -'@sveltejs/kit': minor +'@sveltejs/kit': patch --- fix: prevent infinite loop when calling `pushState`/`replaceState` in effect From e6381c96fb9aafe0b0d8d0e9563dcb2492f4ed4f Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 22 Jun 2025 20:48:30 -0700 Subject: [PATCH 3/5] fix duplicate import --- packages/kit/src/runtime/client/client.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index e371c92f2da9..84beeb95d79a 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -1,5 +1,5 @@ import { BROWSER, DEV } from 'esm-env'; -import { onMount, tick } from 'svelte'; +import { onMount, tick, untrack } from 'svelte'; import { decode_params, decode_pathname, @@ -39,7 +39,6 @@ import { HttpError, Redirect, SvelteKitError } from '../control.js'; import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM, validate_depends } from '../shared.js'; import { get_message, get_status } from '../../utils/error.js'; import { writable } from 'svelte/store'; -import { untrack } from 'svelte'; import { page, update, navigating } from './state.svelte.js'; import { add_data_suffix, add_resolution_suffix } from '../pathname.js'; From 9344ebe398dadf6ac11a786b79ff7fa1e221954b Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Mon, 23 Jun 2025 17:19:11 +0800 Subject: [PATCH 4/5] test for shallow navigation with effects --- .changeset/chatty-pears-notice.md | 2 +- packages/kit/test/apps/basics/src/app.d.ts | 5 ++--- .../push-state/effect/+page.svelte | 12 ++++++++++++ .../replace-state/effect/+page.svelte | 12 ++++++++++++ packages/kit/test/apps/basics/test/client.test.js | 15 +++++++++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/effect/+page.svelte create mode 100644 packages/kit/test/apps/basics/src/routes/shallow-routing/replace-state/effect/+page.svelte diff --git a/.changeset/chatty-pears-notice.md b/.changeset/chatty-pears-notice.md index 6f811b8da9e5..7781f2b07ab1 100644 --- a/.changeset/chatty-pears-notice.md +++ b/.changeset/chatty-pears-notice.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: prevent infinite loop when calling `pushState`/`replaceState` in effect +fix: prevent infinite loop when calling `pushState`/`replaceState` in `$effect` diff --git a/packages/kit/test/apps/basics/src/app.d.ts b/packages/kit/test/apps/basics/src/app.d.ts index f40b6d8c868a..cbfdcaafa47a 100644 --- a/packages/kit/test/apps/basics/src/app.d.ts +++ b/packages/kit/test/apps/basics/src/app.d.ts @@ -10,10 +10,9 @@ declare global { } interface PageState { - active: boolean; + active?: boolean; + count?: number; } - - interface Platform {} } } diff --git a/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/effect/+page.svelte b/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/effect/+page.svelte new file mode 100644 index 000000000000..0bc4747beb5f --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/effect/+page.svelte @@ -0,0 +1,12 @@ + + +

count: {count}

+ diff --git a/packages/kit/test/apps/basics/src/routes/shallow-routing/replace-state/effect/+page.svelte b/packages/kit/test/apps/basics/src/routes/shallow-routing/replace-state/effect/+page.svelte new file mode 100644 index 000000000000..cf298aac8150 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/shallow-routing/replace-state/effect/+page.svelte @@ -0,0 +1,12 @@ + + +

count: {count}

+ diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 63ad753637ec..d68cc96ad3e7 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1477,6 +1477,21 @@ test.describe('Shallow routing', () => { await expect(page.locator('h1')).toHaveText('parent'); await expect(page.locator('p')).toHaveText('active: true'); }); + + // TODO: pushState/replaceState infinite loop in $effect + test('pushState does not loop infinitely in $effect', async ({ page }) => { + await page.goto('/shallow-routing/push-state/effect'); + await expect(page.locator('p')).toHaveText('count: 0'); + await page.locator('button').click(); + await expect(page.locator('p')).toHaveText('count: 1'); + }); + + test('replaceState does not loop infinitely in $effect', async ({ page }) => { + await page.goto('/shallow-routing/replace-state/effect'); + await expect(page.locator('p')).toHaveText('count: 0'); + await page.locator('button').click(); + await expect(page.locator('p')).toHaveText('count: 1'); + }); }); test.describe('reroute', () => { From ab531316e2affd0f6e6aaaed0458079040f3c583 Mon Sep 17 00:00:00 2001 From: Chew Tee Ming Date: Mon, 23 Jun 2025 17:19:40 +0800 Subject: [PATCH 5/5] remove todo comment --- packages/kit/test/apps/basics/test/client.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index d68cc96ad3e7..8e494bb82d0c 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1478,7 +1478,6 @@ test.describe('Shallow routing', () => { await expect(page.locator('p')).toHaveText('active: true'); }); - // TODO: pushState/replaceState infinite loop in $effect test('pushState does not loop infinitely in $effect', async ({ page }) => { await page.goto('/shallow-routing/push-state/effect'); await expect(page.locator('p')).toHaveText('count: 0');