diff --git a/.changeset/big-masks-shave.md b/.changeset/big-masks-shave.md new file mode 100644 index 000000000000..96c18fdb6c73 --- /dev/null +++ b/.changeset/big-masks-shave.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: `hydratable` API diff --git a/documentation/docs/06-runtime/05-hydratable.md b/documentation/docs/06-runtime/05-hydratable.md new file mode 100644 index 000000000000..d6f5d9a1eb76 --- /dev/null +++ b/documentation/docs/06-runtime/05-hydratable.md @@ -0,0 +1,107 @@ +--- +title: Hydratable data +--- + +In Svelte, when you want to render asynchonous content data on the server, you can simply `await` it. This is great! However, it comes with a major pitall: when hydrating that content on the client, Svelte has to redo the asynchronous work, which blocks hydration for however long it takes: + +```svelte + + +
The current environment is: server
', + + props: { environment: 'browser' }, + + async test({ assert, target, variant }) { + const p = target.querySelector('p'); + ok(p); + if (variant === 'hydrate') { + assert.htmlEqual(p.outerHTML, 'The current environment is: server
'); + } else { + assert.htmlEqual(p.outerHTML, 'The current environment is: browser
'); + } + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-custom-transport/main.svelte b/packages/svelte/tests/runtime-runes/samples/hydratable-custom-transport/main.svelte new file mode 100644 index 000000000000..18b7f834676b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-custom-transport/main.svelte @@ -0,0 +1,15 @@ + + +The current environment is: {value}
diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing-imperative/_config.js b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing-imperative/_config.js new file mode 100644 index 000000000000..3990b65087e3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing-imperative/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + skip_no_async: true, + mode: ['async-server', 'hydrate'], + + server_props: { environment: 'server' }, + ssrHtml: 'The current environment is: server
', + + props: { environment: 'browser' }, + + runtime_error: 'hydratable_missing_but_expected_e' +}); diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing-imperative/main.svelte b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing-imperative/main.svelte new file mode 100644 index 000000000000..4784dd13b2a3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing-imperative/main.svelte @@ -0,0 +1,14 @@ + + +The current environment is: {value}
diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing/_config.js b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing/_config.js new file mode 100644 index 000000000000..b04d81d63914 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing/_config.js @@ -0,0 +1,13 @@ +import { ok, test } from '../../test'; + +export default test({ + skip_no_async: true, + mode: ['async-server', 'hydrate'], + + server_props: { environment: 'server' }, + ssrHtml: 'The current environment is: server
', + + props: { environment: 'browser' }, + + runtime_error: 'hydratable_missing_but_expected_e' +}); diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing/main.svelte b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing/main.svelte new file mode 100644 index 000000000000..b7dfc0e7e252 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable-error-on-missing/main.svelte @@ -0,0 +1,14 @@ + + +The current environment is: {value}
diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable/_config.js b/packages/svelte/tests/runtime-runes/samples/hydratable/_config.js new file mode 100644 index 000000000000..57904ef57608 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + skip_no_async: true, + skip_mode: ['server'], + + server_props: { environment: 'server' }, + ssrHtml: 'The current environment is: server
', + + props: { environment: 'browser' }, + + async test({ assert, target, variant }) { + const p = target.querySelector('p'); + ok(p); + if (variant === 'hydrate') { + assert.htmlEqual(p.outerHTML, 'The current environment is: server
'); + } else { + assert.htmlEqual(p.outerHTML, 'The current environment is: browser
'); + } + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/hydratable/main.svelte b/packages/svelte/tests/runtime-runes/samples/hydratable/main.svelte new file mode 100644 index 000000000000..53b9c24f91c1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/hydratable/main.svelte @@ -0,0 +1,9 @@ + + +The current environment is: {value}
diff --git a/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering-imperative/_config.js b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering-imperative/_config.js new file mode 100644 index 000000000000..404260cc66d8 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering-imperative/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + mode: ['async'], + error: 'hydratable_clobbering' +}); diff --git a/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering-imperative/main.svelte b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering-imperative/main.svelte new file mode 100644 index 000000000000..25a1166f8324 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering-imperative/main.svelte @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering/_config.js b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering/_config.js new file mode 100644 index 000000000000..404260cc66d8 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + mode: ['async'], + error: 'hydratable_clobbering' +}); diff --git a/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering/main.svelte b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering/main.svelte new file mode 100644 index 000000000000..764c2c241557 --- /dev/null +++ b/packages/svelte/tests/server-side-rendering/samples/hydratable-clobbering/main.svelte @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/server-side-rendering/test.ts b/packages/svelte/tests/server-side-rendering/test.ts index 7eede332a741..20997cdf6260 100644 --- a/packages/svelte/tests/server-side-rendering/test.ts +++ b/packages/svelte/tests/server-side-rendering/test.ts @@ -81,7 +81,7 @@ const { test, run } = suite_with_variants