diff --git a/packages/svelte/src/internal/server/hydratable.js b/packages/svelte/src/internal/server/hydratable.js index 6347022a45..81f59ab2fd 100644 --- a/packages/svelte/src/internal/server/hydratable.js +++ b/packages/svelte/src/internal/server/hydratable.js @@ -57,8 +57,16 @@ function encode(key, value, unresolved) { entry.serialized = devalue.uneval(entry.value, (value, uneval) => { if (is_promise(value)) { + // we serialize promises as `"${i}"`, because it's impossible for that string + // to occur 'naturally' (since the quote marks would have to be escaped) + // this placeholder is returned synchronously from `uneval`, which includes it in the + // serialized string. Later (at least one microtask from now), when `p.then` runs, it'll + // be replaced. + const placeholder = `"${uid++}"`; const p = value - .then((v) => `r(${uneval(v)})`) + .then((v) => { + entry.serialized = entry.serialized.replace(placeholder, `r(${uneval(v)})`); + }) .catch((devalue_error) => e.hydratable_serialization_failed( key, @@ -66,25 +74,11 @@ function encode(key, value, unresolved) { ) ); - // prevent unhandled rejections from crashing the server - p.catch(() => {}); - - // track which promises are still resolving when render is complete unresolved?.set(p, key); - p.finally(() => unresolved?.delete(p)); - - // we serialize promises as `"${i}"`, because it's impossible for that string - // to occur 'naturally' (since the quote marks would have to be escaped) - const placeholder = `"${uid++}"`; - - (entry.promises ??= []).push( - p - .then((s) => { - entry.serialized = entry.serialized.replace(placeholder, s); - }) - .catch(() => {}) - ); + // prevent unhandled rejections from crashing the server, track which promises are still resolving when render is complete + p.catch(() => {}).finally(() => unresolved?.delete(p)); + (entry.promises ??= []).push(p); return placeholder; } }); diff --git a/packages/svelte/tests/server-side-rendering/samples/hydratable-unserializable/_config.js b/packages/svelte/tests/server-side-rendering/samples/hydratable-unserializable/_config.js new file mode 100644 index 0000000000..79b0c90fe6 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/hydratable-unserializable/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + mode: ['async'], + error: 'hydratable_serialization_failed' +}); diff --git a/packages/svelte/tests/server-side-rendering/samples/hydratable-unserializable/main.svelte b/packages/svelte/tests/server-side-rendering/samples/hydratable-unserializable/main.svelte new file mode 100644 index 0000000000..e104dec12b --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/hydratable-unserializable/main.svelte @@ -0,0 +1,5 @@ + \ No newline at end of file