Skip to content

Commit 3cd9344

Browse files
committed
fix: exclude readonly bindings from reactive state validation
`bind:this` etc only go upwards, and depending on the use case it's fine to connect it to a non-reactive variable
1 parent d73c5b8 commit 3cd9344

File tree

4 files changed

+65
-17
lines changed

4 files changed

+65
-17
lines changed

.changeset/silent-rocks-yell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: exclude `bind:this` from reactive state validation

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,9 +2826,11 @@ export const template_visitors = {
28262826
BindDirective(node, context) {
28272827
const { state, path, visit } = context;
28282828
const expression = node.expression;
2829+
const property = binding_properties[node.name];
28292830

28302831
if (
28312832
expression.type === 'MemberExpression' &&
2833+
(!property || property.bidirectional) &&
28322834
context.state.options.dev &&
28332835
context.state.analysis.runes
28342836
) {
@@ -2859,8 +2861,7 @@ export const template_visitors = {
28592861
/** @type {CallExpression} */
28602862
let call_expr;
28612863

2862-
const property = binding_properties[node.name];
2863-
if (property && property.event) {
2864+
if (property?.event) {
28642865
call_expr = b.call(
28652866
'$.bind_property',
28662867
b.literal(node.name),

packages/svelte/src/compiler/phases/bindings.js

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export const binding_properties = {
1515
// media
1616
currentTime: {
1717
valid_elements: ['audio', 'video'],
18-
omit_in_ssr: true
18+
omit_in_ssr: true,
19+
bidirectional: true
1920
},
2021
duration: {
2122
valid_elements: ['audio', 'video'],
@@ -25,7 +26,8 @@ export const binding_properties = {
2526
focused: {},
2627
paused: {
2728
valid_elements: ['audio', 'video'],
28-
omit_in_ssr: true
29+
omit_in_ssr: true,
30+
bidirectional: true
2931
},
3032
buffered: {
3133
valid_elements: ['audio', 'video'],
@@ -41,15 +43,18 @@ export const binding_properties = {
4143
},
4244
volume: {
4345
valid_elements: ['audio', 'video'],
44-
omit_in_ssr: true
46+
omit_in_ssr: true,
47+
bidirectional: true
4548
},
4649
muted: {
4750
valid_elements: ['audio', 'video'],
48-
omit_in_ssr: true
51+
omit_in_ssr: true,
52+
bidirectional: true
4953
},
5054
playbackRate: {
5155
valid_elements: ['audio', 'video'],
52-
omit_in_ssr: true
56+
omit_in_ssr: true,
57+
bidirectional: true
5358
},
5459
seeking: {
5560
valid_elements: ['audio', 'video'],
@@ -124,11 +129,13 @@ export const binding_properties = {
124129
},
125130
scrollX: {
126131
valid_elements: ['svelte:window'],
127-
omit_in_ssr: true
132+
omit_in_ssr: true,
133+
bidirectional: true
128134
},
129135
scrollY: {
130136
valid_elements: ['svelte:window'],
131-
omit_in_ssr: true
137+
omit_in_ssr: true,
138+
bidirectional: true
132139
},
133140
online: {
134141
valid_elements: ['svelte:window'],
@@ -180,34 +187,41 @@ export const binding_properties = {
180187
omit_in_ssr: true // no corresponding attribute
181188
},
182189
checked: {
183-
valid_elements: ['input']
190+
valid_elements: ['input'],
191+
bidirectional: true
184192
},
185193
group: {
186-
valid_elements: ['input']
194+
valid_elements: ['input'],
195+
bidirectional: true
187196
},
188197
// various
189198
this: {
190199
omit_in_ssr: true
191200
},
192201
innerText: {
193-
invalid_elements: ['svelte:window', 'svelte:document']
202+
invalid_elements: ['svelte:window', 'svelte:document'],
203+
bidirectional: true
194204
},
195205
innerHTML: {
196-
invalid_elements: ['svelte:window', 'svelte:document']
206+
invalid_elements: ['svelte:window', 'svelte:document'],
207+
bidirectional: true
197208
},
198209
textContent: {
199-
invalid_elements: ['svelte:window', 'svelte:document']
210+
invalid_elements: ['svelte:window', 'svelte:document'],
211+
bidirectional: true
200212
},
201213
open: {
202214
event: 'toggle',
203215
bidirectional: true,
204216
valid_elements: ['details']
205217
},
206218
value: {
207-
valid_elements: ['input', 'textarea', 'select']
219+
valid_elements: ['input', 'textarea', 'select'],
220+
bidirectional: true
208221
},
209222
files: {
210223
valid_elements: ['input'],
211-
omit_in_ssr: true
224+
omit_in_ssr: true,
225+
bidirectional: true
212226
}
213227
};

packages/svelte/tests/runtime-runes/samples/binding-property-static/main.svelte

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,38 @@
5252
<Child bind:value={pojo.value} />
5353
<Child bind:value={frozen.value} />
5454

55-
<!-- should not warn -->
55+
<!-- should not warn (because reactive value) -->
5656
<input bind:value={reactive.value} />
5757
<input bind:value={accessors.value} />
5858
<input bind:value={proxy.value} />
5959
<Child bind:value={reactive.value} />
6060
<Child bind:value={accessors.value} />
6161
<Child bind:value={proxy.value} />
62+
63+
<!-- should not warn (because one-way binding) -->
64+
<svelte:window
65+
bind:innerHeight={pojo.value}
66+
bind:innerWidth={pojo.value}
67+
bind:outerHeight={pojo.value}
68+
bind:outerWidth={pojo.value}
69+
bind:online={pojo.value}
70+
bind:devicePixelRatio={pojo.value}
71+
/>
72+
<svelte:document
73+
bind:activeElement={pojo.value}
74+
bind:fullscreenElement={pojo.value}
75+
bind:pointerLockElement={pojo.value}
76+
bind:visibilityState={pojo.value}
77+
/>
78+
<!-- can't test size bindings because it's not available in JSDom https://github.com/jsdom/jsdom/issues/3368 -->
79+
<div bind:this={pojo.value}></div>
80+
<video
81+
bind:duration={pojo.value}
82+
bind:buffered={pojo.value}
83+
bind:played={pojo.value}
84+
bind:seeking={pojo.value}
85+
bind:readyState={pojo.value}
86+
bind:videoHeight={pojo.value}
87+
bind:videoWidth={pojo.value}
88+
></video>
89+
<img bind:naturalHeight={pojo.value} bind:naturalWidth={pojo.value} />

0 commit comments

Comments
 (0)