From fee93bea4a8aad94ebd785c78037990b6ce0529c Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Mon, 27 Oct 2025 10:53:27 +0100 Subject: [PATCH 1/6] fix: also await for `settled` in case there's no fork but there's async work --- .changeset/loud-items-glow.md | 5 +++++ packages/kit/src/runtime/client/client.js | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .changeset/loud-items-glow.md diff --git a/.changeset/loud-items-glow.md b/.changeset/loud-items-glow.md new file mode 100644 index 000000000000..6c5060c2fca2 --- /dev/null +++ b/.changeset/loud-items-glow.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: also await for `settled` in case there's no fork but there's async work diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index ce4fbddb0f93..e465859ad905 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -1742,7 +1742,11 @@ async function navigate({ const promises = [tick()]; // need to render the DOM before we can scroll to the rendered elements and do focus management - // so we wait for the commit if there's one + // svelte.settled is only available in Svelte 5 + if (/** @type {any} */ (svelte).settled) { + promises.push(/** @type {any} */ (svelte).settled()); + } + // if we preloaded we also need to wait for the commit_promises cause settled would revolve immediately in that case if (commit_promise) { promises.push(commit_promise); } From 023bcd8e3c1f9c34d27217e5334635fe34244f81 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 28 Oct 2025 04:41:12 +0100 Subject: [PATCH 2/6] await tick() twice --- packages/kit/src/runtime/client/client.js | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index e465859ad905..4795b3fc26ee 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -540,6 +540,7 @@ async function _preload_data(intent) { try { return svelte.fork(() => { root.$set(result.props); + update(result.props.page); }); } catch { // if it errors, it's because the experimental flag isn't enabled @@ -1729,9 +1730,11 @@ async function navigate({ commit_promise = fork.commit(); } else { root.$set(navigation_result.props); + update(navigation_result.props.page); + + commit_promise = svelte.settled?.(); } - update(navigation_result.props.page); has_navigated = true; } else { initialize(navigation_result, target, false); @@ -1739,19 +1742,13 @@ async function navigate({ const { activeElement } = document; - const promises = [tick()]; + await commit_promise; - // need to render the DOM before we can scroll to the rendered elements and do focus management - // svelte.settled is only available in Svelte 5 - if (/** @type {any} */ (svelte).settled) { - promises.push(/** @type {any} */ (svelte).settled()); - } - // if we preloaded we also need to wait for the commit_promises cause settled would revolve immediately in that case - if (commit_promise) { - promises.push(commit_promise); - } - // we still need to await tick everytime because if there's no async work settled resolves immediately - await Promise.all(promises); + // TODO 3.0 remote — the double tick is probably necessary because + // of some store shenanigans. `settled()` and `f.commit()` + // should resolve after DOM updates in newer versions + await svelte.tick(); + await svelte.tick(); // we reset scroll before dealing with focus, to avoid a flash of unscrolled content let scroll = popped ? popped.scroll : noscroll ? scroll_state() : null; From 13e37866f07db07885ad0d1a51d4d37ccced869a Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 28 Oct 2025 04:46:31 +0100 Subject: [PATCH 3/6] update changeset --- .changeset/loud-items-glow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/loud-items-glow.md b/.changeset/loud-items-glow.md index 6c5060c2fca2..78ee598d4fb1 100644 --- a/.changeset/loud-items-glow.md +++ b/.changeset/loud-items-glow.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix: also await for `settled` in case there's no fork but there's async work +fix: update DOM before running navigate callbacks From 08d06a8ec98a137e7321b4499e50535e8cb14e16 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Tue, 28 Oct 2025 14:07:42 +0800 Subject: [PATCH 4/6] add test --- .../source/pages/on-navigate/+layout.svelte | 25 +++++++++++++++++++ .../source/pages/on-navigate/a/+page.svelte | 1 + .../source/pages/on-navigate/b/+page.svelte | 11 ++++++++ .../kit/test/apps/options/svelte.config.js | 5 ++++ packages/kit/test/apps/options/test/test.js | 21 ++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte create mode 100644 packages/kit/test/apps/options/source/pages/on-navigate/a/+page.svelte create mode 100644 packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte diff --git a/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte b/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte new file mode 100644 index 000000000000..00e4edb0b4ac --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte @@ -0,0 +1,25 @@ + + +
    +
  • a
  • +
  • b
  • +
+ +{@render children()} diff --git a/packages/kit/test/apps/options/source/pages/on-navigate/a/+page.svelte b/packages/kit/test/apps/options/source/pages/on-navigate/a/+page.svelte new file mode 100644 index 000000000000..af21b438c402 --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/on-navigate/a/+page.svelte @@ -0,0 +1 @@ +

Page A

diff --git a/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte b/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte new file mode 100644 index 000000000000..beddac37133a --- /dev/null +++ b/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte @@ -0,0 +1,11 @@ + + +

Page B

diff --git a/packages/kit/test/apps/options/svelte.config.js b/packages/kit/test/apps/options/svelte.config.js index 3c10a2826669..d2e4c2c452cf 100644 --- a/packages/kit/test/apps/options/svelte.config.js +++ b/packages/kit/test/apps/options/svelte.config.js @@ -41,6 +41,11 @@ const config = { router: { resolution: /** @type {'client' | 'server'} */ (process.env.ROUTER_RESOLUTION) || 'client' } + }, + compilerOptions: { + experimental: { + async: true + } } }; diff --git a/packages/kit/test/apps/options/test/test.js b/packages/kit/test/apps/options/test/test.js index 82a30b34f159..832968094f0c 100644 --- a/packages/kit/test/apps/options/test/test.js +++ b/packages/kit/test/apps/options/test/test.js @@ -351,3 +351,24 @@ test.describe('Routing', () => { await expect(page.locator('h2')).toHaveText('target: 0'); }); }); + +test.describe('Async', () => { + test("updates the DOM before onNavigate's promise is resolved", async ({ + page, + javaScriptEnabled + }) => { + test.skip(!javaScriptEnabled); + + await page.goto('/path-base/on-navigate/a'); + + const logs = []; + page.on('console', (msg) => { + logs.push(msg.text()); + }); + + await page.getByRole('link', { name: 'b' }).click(); + + await expect(page.locator('h1', { hasText: 'Page B' })).toBeVisible(); + expect(logs).toEqual(['mounted', 'navigated']); + }); +}); From 5c8230930d5fa4973ed7641db059905d2fe1fa0b Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Tue, 28 Oct 2025 14:09:48 +0800 Subject: [PATCH 5/6] format --- .../options/source/pages/on-navigate/+layout.svelte | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte b/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte index 00e4edb0b4ac..72a6114a9639 100644 --- a/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte +++ b/packages/kit/test/apps/options/source/pages/on-navigate/+layout.svelte @@ -1,8 +1,8 @@ {@render children()} From 827c256c0b4d5255e3bc23407c3b9f5e1f0bce09 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 28 Oct 2025 07:38:59 +0100 Subject: [PATCH 6/6] lint --- .../test/apps/options/source/pages/on-navigate/b/+page.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte b/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte index beddac37133a..0a48299af1f5 100644 --- a/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte +++ b/packages/kit/test/apps/options/source/pages/on-navigate/b/+page.svelte @@ -1,6 +1,7 @@