diff --git a/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md b/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md index 8fefe5d50..ba3a8e7a3 100644 --- a/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md +++ b/apps/svelte.dev/content/docs/svelte/02-runes/02-$state.md @@ -51,7 +51,7 @@ todos.push({ }); ``` -> [!NOTE] When you update properties of proxies, the original object is _not_ mutated. +> [!NOTE] When you update properties of proxies, the original object is _not_ mutated. If you need to use your own proxy handlers in a state proxy, [you should wrap the object _after_ wrapping it in `$state`](https://svelte.dev/playground/hello-world?version=latest#H4sIAAAAAAAACpWR3WoDIRCFX2UqhWyIJL3erAulL9C7XnQLMe5ksbUqOpsfln33YuyGFNJC8UKdc2bOhw7Myk9kJXsJ0nttO9jcR5KEG9AWJDwHdzwxznbaYGTl68Do5JM_FRifuh-9X8Y9Gkq1rYx4q66cJbQUWcmqqIL2VDe2IYMEbvuOikBADi-GJDSkXG-phId0G-frye2DO2psQYDFQ0Ys8gQO350dUkEydEg82T0GOs0nsSG9g2IqgxACZueo2ZUlpdvoDC6N64qsg1QKY8T2bpZp8gpIfbCQ85Zn50Ud82HkeY83uDjspenxv3jXcSDyjPWf9L1vJf0GH666J-jLu1ery4dV257IWXBWGa0-xFDMQdTTn2ScxWKsn86ROsLwQxqrVR5QM84Ij8TKFD2-cUZSm4O2LSt30kQcvwCgCmfZnAIAAA==). Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring: diff --git a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-errors.md b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-errors.md index 3f33e37d2..c7d6ec8ac 100644 --- a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-errors.md +++ b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-errors.md @@ -1,5 +1,17 @@ +### async_derived_orphan + +``` +Cannot create a `$derived(...)` with an `await` expression outside of an effect tree +``` + +In Svelte there are two types of reaction — [`$derived`](/docs/svelte/$derived) and [`$effect`](/docs/svelte/$effect). Deriveds can be created anywhere, because they run _lazily_ and can be [garbage collected](https://developer.mozilla.org/en-US/docs/Glossary/Garbage_collection) if nothing references them. Effects, by contrast, keep running eagerly whenever their dependencies change, until they are destroyed. + +Because of this, effects can only be created inside other effects (or [effect roots](/docs/svelte/$effect#$effect.root), such as the one that is created when you first mount a component) so that Svelte knows when to destroy them. + +Some sleight of hand occurs when a derived contains an `await` expression: Since waiting until we read `{await getPromise()}` to call `getPromise` would be too late, we use an effect to instead call it proactively, notifying Svelte when the value is available. But since we're using an effect, we can only create asynchronous deriveds inside another effect. + ### bind_invalid_checkbox_value ``` @@ -68,12 +80,28 @@ Effect cannot be created inside a `$derived` value that was not itself created i `%rune%` can only be used inside an effect (e.g. during component initialisation) ``` +### effect_pending_outside_reaction + +``` +`$effect.pending()` can only be called inside an effect or derived +``` + ### effect_update_depth_exceeded ``` Maximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops ``` +### flush_sync_in_effect + +``` +Cannot use `flushSync` inside an effect +``` + +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. + +This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6. + ### get_abort_signal_outside_reaction ``` @@ -116,6 +144,14 @@ Rest element properties of `$props()` such as `%property%` are readonly The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files ``` +### set_context_after_init + +``` +`setContext` must be called when a component first initializes, not in a subsequent effect or after an `await` expression +``` + +This restriction only applies when using the `experimental.async` option, which will be active by default in Svelte 6. + ### state_descriptors_fixed ``` diff --git a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-warnings.md b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-warnings.md index fe90b0db3..7548428e9 100644 --- a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-warnings.md +++ b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-warnings.md @@ -34,6 +34,86 @@ function add() { } ``` +### await_reactivity_loss + +``` +Detected reactivity loss when reading `%name%`. This happens when state is read in an async function after an earlier `await` +``` + +Svelte's signal-based reactivity works by tracking which bits of state are read when a template or `$derived(...)` expression executes. If an expression contains an `await`, Svelte transforms it such that any state _after_ the `await` is also tracked — in other words, in a case like this... + +```js +let a = Promise.resolve(1); +let b = 2; +// ---cut--- +let total = $derived(await a + b); +``` + +...both `a` and `b` are tracked, even though `b` is only read once `a` has resolved, after the initial execution. + +This does _not_ apply to an `await` that is not 'visible' inside the expression. In a case like this... + +```js +let a = Promise.resolve(1); +let b = 2; +// ---cut--- +async function sum() { + return await a + b; +} + +let total = $derived(await sum()); +``` + +...`total` will depend on `a` (which is read immediately) but not `b` (which is not). The solution is to pass the values into the function: + +```js +let a = Promise.resolve(1); +let b = 2; +// ---cut--- +/** + * @param {Promise} a + * @param {number} b + */ +async function sum(a, b) { + return await a + b; +} + +let total = $derived(await sum(a, b)); +``` + +### await_waterfall + +``` +An async derived, `%name%` (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app +``` + +In a case like this... + +```js +async function one() { return 1 } +async function two() { return 2 } +// ---cut--- +let a = $derived(await one()); +let b = $derived(await two()); +``` + +...the second `$derived` will not be created until the first one has resolved. Since `await two()` does not depend on the value of `a`, this delay, often described as a 'waterfall', is unnecessary. + +(Note that if the values of `await one()` and `await two()` subsequently change, they can do so concurrently — the waterfall only occurs when the deriveds are first created.) + +You can solve this by creating the promises first and _then_ awaiting them: + +```js +async function one() { return 1 } +async function two() { return 2 } +// ---cut--- +let aPromise = $derived(one()); +let bPromise = $derived(two()); + +let a = $derived(await aPromise); +let b = $derived(await bPromise); +``` + ### binding_property_non_reactive ``` diff --git a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/compile-errors.md b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/compile-errors.md index db848a029..20f57770d 100644 --- a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/compile-errors.md +++ b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/compile-errors.md @@ -480,6 +480,12 @@ Expected token %token% Expected whitespace ``` +### experimental_async + +``` +Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless the `experimental.async` compiler option is `true` +``` + ### export_undefined ``` @@ -534,6 +540,12 @@ The arguments keyword cannot be used within the template or at the top level of %message% ``` +### legacy_await_invalid + +``` +Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless in runes mode +``` + ### legacy_export_invalid ``` diff --git a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/shared-errors.md b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/shared-errors.md index 6c31aaafd..de34b3f5d 100644 --- a/apps/svelte.dev/content/docs/svelte/98-reference/.generated/shared-errors.md +++ b/apps/svelte.dev/content/docs/svelte/98-reference/.generated/shared-errors.md @@ -1,5 +1,25 @@ +### await_outside_boundary + +``` +Cannot await outside a `` with a `pending` snippet +``` + +The `await` keyword can only appear in a `$derived(...)` or template expression, or at the top level of a component's `