From d22a9ad76e1c6f23b6ef2d2cd8b02360758c585f Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Thu, 23 Oct 2025 22:36:11 +0200 Subject: [PATCH 1/4] fix: wait an extra microtask in dev before calling `$$_init_$$` --- .changeset/empty-animals-retire.md | 5 +++++ packages/kit/src/exports/vite/index.js | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 .changeset/empty-animals-retire.md diff --git a/.changeset/empty-animals-retire.md b/.changeset/empty-animals-retire.md new file mode 100644 index 000000000000..e75b235ac854 --- /dev/null +++ b/.changeset/empty-animals-retire.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: wait an extra microtask in dev before calling `$$_init_$$` diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 4a441b23d4d5..c5dfe2647d33 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -697,6 +697,12 @@ async function kit({ svelte_config }) { remotes.push(remote); if (opts?.ssr) { + // we need to add an `await Promise.resolve()` because if the user imports this function + // on the client AND in a load function when loading the client module we will trigger + // an ssrLoadModule during dev. During a link preload the the module can be mistakenly + // loaded and transformed twice and the first time all its exports would be undefined + // triggering a dev server error. By adding a microtask we ensure that the module is fully loaded + // Extra newlines to prevent syntax errors around missing semicolons or comments code += '\n\n' + @@ -704,6 +710,8 @@ async function kit({ svelte_config }) { import * as $$_self_$$ from './${path.basename(id)}'; import { init_remote_functions as $$_init_$$ } from '@sveltejs/kit/internal'; + ${dev_server ? 'await Promise.resolve()' : ''} + $$_init_$$($$_self_$$, ${s(file)}, ${s(remote.hash)}); for (const [name, fn] of Object.entries($$_self_$$)) { From 349e3a3921d46d2005e16a868854e585fa5880d9 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Wed, 5 Nov 2025 14:44:16 +0800 Subject: [PATCH 2/4] add test --- .../basics/src/routes/remote/dev/+page.svelte | 5 +++++ .../routes/remote/dev/preload/+page.server.js | 7 +++++++ .../src/routes/remote/dev/preload/+page.svelte | 8 ++++++++ .../routes/remote/dev/preload/example.remote.js | 7 +++++++ .../src/routes/remote/dev/preload/schema.js | 3 +++ .../kit/test/apps/basics/test/client.test.js | 16 +++++++++++++++- 6 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 packages/kit/test/apps/basics/src/routes/remote/dev/+page.svelte create mode 100644 packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.server.js create mode 100644 packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.svelte create mode 100644 packages/kit/test/apps/basics/src/routes/remote/dev/preload/example.remote.js create mode 100644 packages/kit/test/apps/basics/src/routes/remote/dev/preload/schema.js diff --git a/packages/kit/test/apps/basics/src/routes/remote/dev/+page.svelte b/packages/kit/test/apps/basics/src/routes/remote/dev/+page.svelte new file mode 100644 index 000000000000..ba83ae74c565 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/dev/+page.svelte @@ -0,0 +1,5 @@ + + +preload diff --git a/packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.server.js b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.server.js new file mode 100644 index 000000000000..102d1732b736 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.server.js @@ -0,0 +1,7 @@ +import { example } from './example.remote'; + +export const load = async () => { + return { + example: await example('bar') + }; +}; diff --git a/packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.svelte b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.svelte new file mode 100644 index 000000000000..7f89d533c468 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/+page.svelte @@ -0,0 +1,8 @@ + + +

{data.example}

+ diff --git a/packages/kit/test/apps/basics/src/routes/remote/dev/preload/example.remote.js b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/example.remote.js new file mode 100644 index 000000000000..d455c61cc022 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/example.remote.js @@ -0,0 +1,7 @@ +import { query } from '$app/server'; +import { schema } from './schema'; + +export const example = query(schema, async (param) => { + await new Promise((resolve) => setTimeout(resolve, 1000)); + return 'foo' + param; +}); diff --git a/packages/kit/test/apps/basics/src/routes/remote/dev/preload/schema.js b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/schema.js new file mode 100644 index 000000000000..b057fd097443 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/dev/preload/schema.js @@ -0,0 +1,3 @@ +import * as v from 'valibot'; + +export const schema = v.string(); diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index df4c519275e7..253322d03a0d 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1786,8 +1786,22 @@ test.describe('routing', () => { }); }); -// have to run in serial because commands mutate in-memory data on the server test.describe('remote functions', () => { + test('preloading data works when the page component and server load both import a remote function', async ({ page }) => { + test.skip(!process.env.DEV, 'remote functions are only analysed in dev mode'); + await page.goto('/remote/dev'); + await page.locator('a[href="/remote/dev/preload"]').hover(); + await Promise.all([ + page.waitForTimeout(100), // wait for preloading to start + page.waitForLoadState('networkidle') // wait for preloading to finish + ]); + await page.click('a[href="/remote/dev/preload"]'); + await expect(page.locator('p')).toHaveText('foobar'); + }); +}); + +// have to run in serial because commands mutate in-memory data on the server +test.describe('remote function mutations', () => { test.describe.configure({ mode: 'default' }); test.afterEach(async ({ page }) => { if (page.url().endsWith('/remote')) { From 0f9e1c193d778bdf0e0de95f52099f650c911d7b Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Wed, 5 Nov 2025 14:46:03 +0800 Subject: [PATCH 3/4] format --- packages/kit/test/apps/basics/test/client.test.js | 4 +++- 1 file changed, 3 insertions(+), 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 253322d03a0d..059e3afed201 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1787,7 +1787,9 @@ test.describe('routing', () => { }); test.describe('remote functions', () => { - test('preloading data works when the page component and server load both import a remote function', async ({ page }) => { + test('preloading data works when the page component and server load both import a remote function', async ({ + page + }) => { test.skip(!process.env.DEV, 'remote functions are only analysed in dev mode'); await page.goto('/remote/dev'); await page.locator('a[href="/remote/dev/preload"]').hover(); From 3b94b9c1ddd40f122f00e0af7349fb48bc96145e Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Wed, 5 Nov 2025 18:35:18 +0800 Subject: [PATCH 4/4] Update index.js --- packages/kit/src/exports/vite/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 0ec67410589a..14a1103f6a61 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -700,7 +700,7 @@ async function kit({ svelte_config }) { if (opts?.ssr) { // we need to add an `await Promise.resolve()` because if the user imports this function // on the client AND in a load function when loading the client module we will trigger - // an ssrLoadModule during dev. During a link preload the the module can be mistakenly + // an ssrLoadModule during dev. During a link preload, the module can be mistakenly // loaded and transformed twice and the first time all its exports would be undefined // triggering a dev server error. By adding a microtask we ensure that the module is fully loaded