Skip to content

Commit 4b5b108

Browse files
committed
docs: more details for errors/warnings on the site
Related to #11305
1 parent c1c59e7 commit 4b5b108

File tree

12 files changed

+486
-0
lines changed

12 files changed

+486
-0
lines changed

documentation/docs/98-reference/.generated/client-warnings.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,31 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
6666
The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value
6767
```
6868

69+
Certain attributes like `src` on an `<img>` element will not be repaired during hydration, i.e. the server value will be kept. That's because for some attributes it is very expensive to properly calculate whether or not their value has really changed.
70+
71+
To fix this, either silence the warning with an ignore comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:
72+
73+
```svelte
74+
<script>
75+
let { src } = $props();
76+
77+
if (typeof window !== 'undefined') {
78+
// stash the value...
79+
const initial = src;
80+
81+
// unset it...
82+
src = undefined;
83+
84+
$effect(() => {
85+
// ...and reset after we've mounted
86+
src = initial;
87+
});
88+
}
89+
</script>
90+
91+
<img {src} />
92+
```
93+
6994
### hydration_html_changed
7095
7196
```
@@ -76,6 +101,31 @@ The value of an `{@html ...}` block changed between server and client renders. T
76101
The value of an `{@html ...}` block %location% changed between server and client renders. The client value will be ignored in favour of the server value
77102
```
78103
104+
If the a `{@html ...}` value changes between the server and the client, it will not be repaired during hydration, i.e. the server value will be kept. That's because it is very expensive to properly calculate whether or not their value have really changed.
105+
106+
To fix this, either silence the warning with an ignore comment, or ensure that the value stays the same between server and client. If you really need the value to change on hydration, you can force an update like this:
107+
108+
```svelte
109+
<script>
110+
let { markup } = $props();
111+
112+
if (typeof window !== 'undefined') {
113+
// stash the value...
114+
const initial = markup;
115+
116+
// unset it...
117+
markup = undefined;
118+
119+
$effect(() => {
120+
// ...and reset after we've mounted
121+
markup = initial;
122+
});
123+
}
124+
</script>
125+
126+
{@html markup}
127+
```
128+
79129
### hydration_mismatch
80130
81131
```
@@ -86,6 +136,10 @@ Hydration failed because the initial UI does not match what was rendered on the
86136
Hydration failed because the initial UI does not match what was rendered on the server. The error occurred near %location%
87137
```
88138
139+
This warning is thrown when Svelte encounters an error while hydrating the HTML from the server. During hydration, Svelte walks the DOM, expecting a certain structure. If that structure is different (for example because the HTML was repaired by the DOM because of invalid HTML), then Svelte will run into issues, resulting in this warning.
140+
141+
During development, this error is often preceeded by a `console.error` detailing the offending HTML, which needs fixing.
142+
89143
### invalid_raw_snippet_render
90144
91145
```
@@ -110,6 +164,10 @@ Tried to unmount a component that was not mounted
110164
%parent% passed a value to %child% with `bind:`, but the value is owned by %owner%. Consider creating a binding between %owner% and %parent%
111165
```
112166

167+
Consider three components `GrandParent`, `Parent` and `Child`. If you do `<GrandParent bind:value>`, inside `GrandParent` pass on the variable via `<Parent {value} />` (note the missing `bind:`) and then do `<Child bind:value>` inside `Parent`, this warning is thrown.
168+
169+
To fix it, `bind:` to the value instead of just passing a property (i.e. in this example do `<Parent bind:value />`).
170+
113171
### ownership_invalid_mutation
114172

115173
```
@@ -120,6 +178,32 @@ Mutating a value outside the component that created it is strongly discouraged.
120178
%component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
121179
```
122180

181+
Consider the following code:
182+
183+
```svelte
184+
<!--- file: App.svelte --->
185+
<script>
186+
import Child from './Child.svelte';
187+
let person = $state({ name: 'Florida', surname: 'Man' });
188+
</script>
189+
190+
<Child {person} />
191+
```
192+
193+
```svelte
194+
<!--- file: Child.svelte --->
195+
<script>
196+
let { person } = $props();
197+
</script>
198+
199+
<input bind:value={person.name}>
200+
<input bind:value={person.surname}>
201+
```
202+
203+
`Child` is mutating `person` which is owned by `App` without being explicitly "allowed" to do so. This is strongly discouraged since it can create code that is hard to reason about at scale ("who mutated this value?"), hence the warning.
204+
205+
To fix it, either create callback props to communicate via events with `App`, or mark `person` as [`$bindable`]($bindable).
206+
123207
### reactive_declaration_non_reactive_property
124208
125209
```

documentation/docs/98-reference/.generated/compile-warnings.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,10 @@ Empty block
610610
Unused CSS selector "%name%"
611611
```
612612

613+
Svelte traverses both the template and the `<style>` tag to find out which of the CSS selectors are actually in use. It will prune (i.e. remove) those selectors which appear unused and warn you about it.
614+
615+
In some situations Svelte may be too strict and you _know_ that the selector is used. In this case, you can use [`:global` or `:global(...)`](global-styles) to prevent them from being pruned.
616+
613617
### element_invalid_self_closing_tag
614618

615619
```
@@ -622,6 +626,8 @@ Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...>
622626
Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead
623627
```
624628

629+
See [the migration guide](v5-migration-guide#Event-changes) for more info.
630+
625631
### export_let_unused
626632

627633
```
@@ -640,6 +646,8 @@ Component has unused export property '%name%'. If it is for external reference o
640646
Svelte 5 components are no longer classes. Instantiate them using `mount` or `hydrate` (imported from 'svelte') instead.
641647
```
642648

649+
See the [migration guide](v5-migration-guide#Components-are-no-longer-classes) for more info.
650+
643651
### node_invalid_placement_ssr
644652

645653
```
@@ -660,6 +668,30 @@ This code will work when the component is rendered on the client (which is why t
660668
`%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
661669
```
662670

671+
This warning is thrown when the compiler detects the following:
672+
- a variable was declared without `$state` or `$state.raw`
673+
- the variable is reassigned
674+
- the variable is read in a reactive context
675+
676+
In this case, changing the value will not correctly trigger updates. Example:
677+
678+
```svelte
679+
<script>
680+
let reactive = $state('reactive');
681+
let stale = 'stale';
682+
</script>
683+
684+
<p>This value updates: {reactive}</p>
685+
<p>This value does not update: {stale}</p>
686+
687+
<button onclick={() => {
688+
stale = 'updated';
689+
reactive = 'updated';
690+
}}>update</button>
691+
```
692+
693+
To fix this, wrap your variable declaration with `$state`.
694+
663695
### options_deprecated_accessors
664696

665697
```
@@ -732,6 +764,12 @@ Reassignments of module-level declarations will not cause reactive statements to
732764
`context="module"` is deprecated, use the `module` attribute instead
733765
```
734766

767+
```svelte
768+
<script ---context="module"--- +++context+++>
769+
let foo = 'bar';
770+
</script>
771+
```
772+
735773
### script_unknown_attribute
736774

737775
```
@@ -744,12 +782,78 @@ Unrecognized attribute — should be one of `generics`, `lang` or `module`. If t
744782
Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead
745783
```
746784

785+
See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more info.
786+
747787
### state_referenced_locally
748788

749789
```
750790
State referenced in its own scope will never update. Did you mean to reference it inside a closure?
751791
```
752792

793+
This warning is thrown when the compiler detects the following:
794+
- A reactive variable is declared
795+
- the variable is reassigned
796+
- the variable is referenced inside the same scope it is declared and it is a non-reactive context
797+
798+
In this case, the state reassignment will not be noticed by whatever you passed it to. For example, if you pass the state to a function, that function will not notice the updates:
799+
800+
```svelte
801+
<!--- Parent.svelte --->
802+
<script>
803+
import { setContext } from 'svelte';
804+
805+
let count = $state(0);
806+
// warning: state referenced locally
807+
setContext('count', count);
808+
</script>
809+
810+
<button onclick={() => count++}>
811+
increment
812+
</button>
813+
```
814+
815+
```svelte
816+
<!--- Child.svelte --->
817+
<script>
818+
import { getContext } from 'svelte';
819+
820+
const count = getContext('count');
821+
</script>
822+
823+
<!-- This will never update -->
824+
<p>The count is {count}</p>
825+
```
826+
827+
To fix this, reference the variable such that it is lazily evaluated. For the above example, this can be achieved by wrapping the count in a function:
828+
829+
```svelte
830+
<!--- Parent.svelte --->
831+
<script>
832+
import { setContext } from 'svelte';
833+
834+
let count = $state(0);
835+
setContext('count', () => count);
836+
</script>
837+
838+
<button onclick={() => count++}>
839+
increment
840+
</button>
841+
```
842+
843+
```svelte
844+
<!--- Child.svelte --->
845+
<script>
846+
import { getContext } from 'svelte';
847+
848+
const count = getContext('count');
849+
</script>
850+
851+
<!-- This will update -->
852+
<p>The count is {count()}</p>
853+
```
854+
855+
For more info, see [the docs on `$state`]($state#Passing-state-into-functions)
856+
753857
### store_rune_conflict
754858

755859
```
@@ -805,6 +909,8 @@ A derived value may be used in other contexts:
805909
`<svelte:self>` is deprecated — use self-imports (e.g. `import %name% from './%basename%'`) instead
806910
```
807911

912+
See [the note in the docs](legacy-svelte-self) for more info.
913+
808914
### unknown_code
809915

810916
```

documentation/docs/98-reference/.generated/server-errors.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
```
66
`%name%(...)` is not available on the server
77
```
8+
9+
Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during the server render.

documentation/docs/98-reference/.generated/shared-errors.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,54 @@
66
Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead
77
```
88

9+
This error would be thrown in a setup like this:
10+
11+
```svelte
12+
<!--- Parent.svelte --->
13+
<List {items} let:entry>
14+
<span>{entry}</span>
15+
</List>
16+
```
17+
18+
```svelte
19+
<!--- List.svelte --->
20+
<script>
21+
let { items, children } = $props();
22+
</script>
23+
24+
<ul>
25+
{#each items as item}
26+
<li>{@render children(item)}</li>
27+
{/each}
28+
</ul>
29+
```
30+
31+
Here, `List.svelte` is using `{@render children(item)` which means it expects `Parent.svelte` to use snippets. Instead, `Parent.svelte` uses the deprecated `let:` directive. This combination of APIs is incompatible, hence the error.
32+
933
### lifecycle_outside_component
1034

1135
```
1236
`%name%(...)` can only be used during component initialisation
1337
```
1438

39+
Certain lifecycle methods can only be used during component initialisation. To fix this, make sure you're invoking the method inside the _top level of the instance script_ of your component.
40+
41+
```svelte
42+
<script>
43+
import { onMount } from 'svelte';
44+
45+
function handleClick() {
46+
// This is wrong
47+
onMount(() => {})
48+
}
49+
50+
// This is correct
51+
onMount(() => {})
52+
</script>
53+
54+
<button onclick={handleClick}>click me</button>
55+
```
56+
1557
### store_invalid_shape
1658

1759
```

documentation/docs/98-reference/.generated/shared-warnings.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
`<svelte:element this="%tag%">` is a void element — it cannot have content
77
```
88

9+
Elements such as `<input>` cannot have content, any children passed to these elements will be ignored.
10+
911
### state_snapshot_uncloneable
1012

1113
```
@@ -17,3 +19,10 @@ The following properties cannot be cloned with `$state.snapshot` — the return
1719
1820
%properties%
1921
```
22+
23+
`$state.snapshot` tries to clone the given value in order to return a reference that no longer changes. Certain objects may not be cloneable, in which case the original value is returned. In the following example, `property` is cloned, but `window` is not, because DOM elements are uncloneable:
24+
25+
```js
26+
const state = $state({ property: 'this is cloneable', window })
27+
const snapshot = $state.snapshot();
28+
```

0 commit comments

Comments
 (0)