diff --git a/.changeset/large-squids-pull.md b/.changeset/large-squids-pull.md new file mode 100644 index 000000000000..ca7f00a02d16 --- /dev/null +++ b/.changeset/large-squids-pull.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: don't wait for remote functions that are not awaited in the template diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 4a6b80be0373..f7d1c860bc04 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -493,7 +493,30 @@ export async function render_response({ if (!info.id) continue; for (const key in cache) { - remote[create_remote_key(info.id, key)] = await cache[key]; + const remote_key = create_remote_key(info.id, key); + + if (event_state.refreshes?.[remote_key] !== undefined) { + // This entry was refreshed/set by a command or form action. + // Always await it so the mutation result is serialized. + remote[remote_key] = await cache[key]; + } else { + // Don't block the response on pending remote data - if a query + // hasn't settled yet, it wasn't awaited in the template (or is behind a pending boundary). + const result = await Promise.race([ + Promise.resolve(cache[key]).then( + (v) => /** @type {const} */ ({ settled: true, value: v }), + (e) => /** @type {const} */ ({ settled: true, error: e }) + ), + new Promise((resolve) => { + queueMicrotask(() => resolve(/** @type {const} */ ({ settled: false }))); + }) + ]); + + if (result.settled) { + if ('error' in result) throw result.error; + remote[remote_key] = result.value; + } + } } } diff --git a/packages/kit/test/apps/async/src/routes/remote/query-boundary/+page.svelte b/packages/kit/test/apps/async/src/routes/remote/query-boundary/+page.svelte new file mode 100644 index 000000000000..6b4aa6de9dcc --- /dev/null +++ b/packages/kit/test/apps/async/src/routes/remote/query-boundary/+page.svelte @@ -0,0 +1,14 @@ + + +
{await get_fast_data()}
+loading delayed
+ {/snippet} +{await delayed}
+