Skip to content

Commit 3a7b9f6

Browse files
Sync svelte docs (#1683)
1 parent 92cc06a commit 3a7b9f6

File tree

9 files changed

+311
-4
lines changed

9 files changed

+311
-4
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
NOTE: do not edit this file, it is generated in apps/svelte.dev/scripts/sync-docs/index.ts
3+
title: Hydratable data
4+
---
5+
6+
In Svelte, when you want to render asynchronous content data on the server, you can simply `await` it. This is great! However, it comes with a pitfall: when hydrating that content on the client, Svelte has to redo the asynchronous work, which blocks hydration for however long it takes:
7+
8+
```svelte
9+
<script>
10+
import { getUser } from 'my-database-library';
11+
12+
// This will get the user on the server, render the user's name into the h1,
13+
// and then, during hydration on the client, it will get the user _again_,
14+
// blocking hydration until it's done.
15+
const user = await getUser();
16+
</script>
17+
18+
<h1>{user.name}</h1>
19+
```
20+
21+
That's silly, though. If we've already done the hard work of getting the data on the server, we don't want to get it again during hydration on the client. `hydratable` is a low-level API built to solve this problem. You probably won't need this very often -- it will be used behind the scenes by whatever datafetching library you use. For example, it powers [remote functions in SvelteKit](/docs/kit/remote-functions).
22+
23+
To fix the example above:
24+
25+
```svelte
26+
<script>
27+
import { hydratable } from 'svelte';
28+
import { getUser } from 'my-database-library';
29+
30+
// During server rendering, this will serialize and stash the result of `getUser`, associating
31+
// it with the provided key and baking it into the `head` content. During hydration, it will
32+
// look for the serialized version, returning it instead of running `getUser`. After hydration
33+
// is done, if it's called again, it'll simply invoke `getUser`.
34+
const user = await hydratable('user', () => getUser());
35+
</script>
36+
37+
<h1>{user.name}</h1>
38+
```
39+
40+
This API can also be used to provide access to random or time-based values that are stable between server rendering and hydration. For example, to get a random number that doesn't update on hydration:
41+
42+
```ts
43+
import { hydratable } from 'svelte';
44+
const rand = hydratable('random', () => Math.random());
45+
```
46+
47+
If you're a library author, be sure to prefix the keys of your `hydratable` values with the name of your library so that your keys don't conflict with other libraries.
48+
49+
## Serialization
50+
51+
All data returned from a `hydratable` function must be serializable. But this doesn't mean you're limited to JSON — Svelte uses [`devalue`](https://npmjs.com/package/devalue), which can serialize all sorts of things including `Map`, `Set`, `URL`, and `BigInt`. Check the documentation page for a full list. In addition to these, thanks to some Svelte magic, you can also fearlessly use promises:
52+
53+
```svelte
54+
<script>
55+
import { hydratable } from 'svelte';
56+
const promises = hydratable('random', () => {
57+
return {
58+
one: Promise.resolve(1),
59+
two: Promise.resolve(2)
60+
}
61+
});
62+
</script>
63+
64+
{await promises.one}
65+
{await promises.two}
66+
```

apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-errors.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,16 @@ $effect(() => {
130130

131131
Often when encountering this issue, the value in question shouldn't be state (for example, if you are pushing to a `logs` array in an effect, make `logs` a normal array rather than `$state([])`). In the rare cases where you really _do_ need to write to state in an effect — [which you should avoid]($effect#When-not-to-use-$effect) — you can read the state with [untrack](svelte#untrack) to avoid adding it as a dependency.
132132

133-
### experimental_async_fork
133+
### flush_sync_in_effect
134134

135135
```
136-
Cannot use `fork(...)` unless the `experimental.async` compiler option is `true`
136+
Cannot use `flushSync` inside an effect
137137
```
138138

139+
The `flushSync()` function can be used to flush any pending effects synchronously. It cannot be used if effects are currently being flushed — in other words, you can call it after a state change but _not_ inside an effect.
140+
141+
This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6.
142+
139143
### fork_discarded
140144

141145
```
@@ -154,6 +158,25 @@ Cannot create a fork inside an effect or when state changes are pending
154158
`getAbortSignal()` can only be called inside an effect or derived
155159
```
156160

161+
### hydratable_missing_but_required
162+
163+
```
164+
Expected to find a hydratable with key `%key%` during hydration, but did not.
165+
```
166+
167+
This can happen if you render a hydratable on the client that was not rendered on the server, and means that it was forced to fall back to running its function blockingly during hydration. This is bad for performance, as it blocks hydration until the asynchronous work completes.
168+
169+
```svelte
170+
<script>
171+
import { hydratable } from 'svelte';
172+
173+
if (BROWSER) {
174+
// bad! nothing can become interactive until this asynchronous work is done
175+
await hydratable('foo', get_slow_random_number);
176+
}
177+
</script>
178+
```
179+
157180
### hydration_failed
158181

159182
```

apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-warnings.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
140140
%handler% should be a function. Did you mean to %suggestion%?
141141
```
142142

143+
### hydratable_missing_but_expected
144+
145+
```
146+
Expected to find a hydratable with key `%key%` during hydration, but did not.
147+
```
148+
149+
This can happen if you render a hydratable on the client that was not rendered on the server, and means that it was forced to fall back to running its function blockingly during hydration. This is bad for performance, as it blocks hydration until the asynchronous work completes.
150+
151+
```svelte
152+
<script>
153+
import { hydratable } from 'svelte';
154+
155+
if (BROWSER) {
156+
// bad! nothing can become interactive until this asynchronous work is done
157+
await hydratable('foo', get_slow_random_number);
158+
}
159+
</script>
160+
```
161+
143162
### hydration_attribute_changed
144163
145164
```

apps/svelte.dev/content/docs/svelte/98-reference/.generated/server-errors.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
22

3+
### async_local_storage_unavailable
4+
5+
```
6+
The node API `AsyncLocalStorage` is not available, but is required to use async server rendering.
7+
```
8+
9+
Some platforms require configuration flags to enable this API. Consult your platform's documentation.
10+
311
### await_invalid
412

513
```
@@ -14,10 +22,51 @@ You (or the framework you're using) called [`render(...)`](svelte-server#render)
1422
The `html` property of server render results has been deprecated. Use `body` instead.
1523
```
1624

25+
### hydratable_clobbering
26+
27+
```
28+
Attempted to set `hydratable` with key `%key%` twice with different values.
29+
30+
%stack%
31+
```
32+
33+
This error occurs when using `hydratable` multiple times with the same key. To avoid this, you can:
34+
- Ensure all invocations with the same key result in the same value
35+
- Update the keys to make both instances unique
36+
37+
```svelte
38+
<script>
39+
import { hydratable } from 'svelte';
40+
41+
// which one should "win" and be serialized in the rendered response?
42+
const one = hydratable('not-unique', () => 1);
43+
const two = hydratable('not-unique', () => 2);
44+
</script>
45+
```
46+
47+
### hydratable_serialization_failed
48+
49+
```
50+
Failed to serialize `hydratable` data for key `%key%`.
51+
52+
`hydratable` can serialize anything [`uneval` from `devalue`](https://npmjs.com/package/uneval) can, plus Promises.
53+
54+
Cause:
55+
%stack%
56+
```
57+
1758
### lifecycle_function_unavailable
1859

1960
```
2061
`%name%(...)` is not available on the server
2162
```
2263

2364
Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render.
65+
66+
### server_context_required
67+
68+
```
69+
Could not resolve `render` context.
70+
```
71+
72+
Certain functions such as `hydratable` cannot be invoked outside of a `render(...)` call, such as at the top level of a module.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
2+
3+
### unresolved_hydratable
4+
5+
```
6+
A `hydratable` value with key `%key%` was created, but at least part of it was not used during the render.
7+
8+
The `hydratable` was initialized in:
9+
%stack%
10+
```
11+
12+
The most likely cause of this is creating a `hydratable` in the `script` block of your component and then `await`ing
13+
the result inside a `svelte:boundary` with a `pending` snippet:
14+
15+
```svelte
16+
<script>
17+
import { hydratable } from 'svelte';
18+
import { getUser } from '$lib/get-user.js';
19+
20+
const user = hydratable('user', getUser);
21+
</script>
22+
23+
<svelte:boundary>
24+
<h1>{(await user).name}</h1>
25+
26+
{#snippet pending()}
27+
<div>Loading...</div>
28+
{/snippet}
29+
</svelte:boundary>
30+
```
31+
32+
Consider inlining the `hydratable` call inside the boundary so that it's not called on the server.
33+
34+
Note that this can also happen when a `hydratable` contains multiple promises and some but not all of them have been used.

apps/svelte.dev/content/docs/svelte/98-reference/.generated/shared-errors.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
22

3+
### experimental_async_required
4+
5+
```
6+
Cannot use `%name%(...)` unless the `experimental.async` compiler option is `true`
7+
```
8+
39
### invalid_default_snippet
410

511
```

apps/svelte.dev/content/docs/svelte/98-reference/20-svelte.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
getAllContexts,
2222
getContext,
2323
hasContext,
24+
hydratable,
2425
hydrate,
2526
mount,
2627
onDestroy,
@@ -433,6 +434,18 @@ function hasContext(key: any): boolean;
433434

434435

435436

437+
## hydratable
438+
439+
<div class="ts-block">
440+
441+
```dts
442+
function hydratable<T>(key: string, fn: () => T): T;
443+
```
444+
445+
</div>
446+
447+
448+
436449
## hydrate
437450

438451
Hydrates a component on the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component

0 commit comments

Comments
 (0)