Skip to content

Commit b8f3c49

Browse files
authored
fix: improve event delegation handler hoisting (#9929)
* fix: improve event delegation handler hoisting * fixes
1 parent 59c7487 commit b8f3c49

File tree

6 files changed

+50
-2
lines changed

6 files changed

+50
-2
lines changed

.changeset/real-guests-do.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: improve event delegation handler hoisting

packages/svelte/src/compiler/phases/1-parse/utils/html.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ function validate_code(code) {
121121

122122
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
123123

124+
const interactive_elements = new Set([
125+
'a',
126+
'button',
127+
'iframe',
128+
'embed',
129+
'input',
130+
'select',
131+
'textarea'
132+
]);
133+
124134
/** @type {Record<string, Set<string>>} */
125135
const disallowed_contents = {
126136
li: new Set(['li']),
@@ -143,6 +153,10 @@ const disallowed_contents = {
143153
th: new Set(['td', 'th', 'tr'])
144154
};
145155

156+
for (const interactive_element of interactive_elements) {
157+
disallowed_contents[interactive_element] = interactive_elements;
158+
}
159+
146160
// can this be a child of the parent element, or does it implicitly
147161
// close it, like `<li>one<li>two`?
148162

packages/svelte/src/compiler/phases/2-analyze/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ function get_delegated_event(node, context) {
166166
return non_hoistable;
167167
}
168168

169+
const visited_references = new Set();
169170
const scope = target_function.metadata.scope;
170171
for (const [reference] of scope.references) {
171172
// Bail-out if the arguments keyword is used
@@ -174,6 +175,15 @@ function get_delegated_event(node, context) {
174175
}
175176
const binding = scope.get(reference);
176177

178+
// If we have multiple references to the same store using $ prefix, bail out.
179+
if (
180+
binding !== null &&
181+
binding.kind === 'store_sub' &&
182+
visited_references.has(reference.slice(1))
183+
) {
184+
return non_hoistable;
185+
}
186+
177187
if (
178188
binding !== null &&
179189
// Bail-out if the the binding is a rest param
@@ -188,6 +198,7 @@ function get_delegated_event(node, context) {
188198
) {
189199
return non_hoistable;
190200
}
201+
visited_references.add(reference);
191202
}
192203
return { type: 'hoistable', function: target_function };
193204
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,7 @@ function get_hoistable_params(node, context) {
363363
binding.kind === 'prop' &&
364364
!binding.reassigned &&
365365
binding.initial === null &&
366-
!context.state.analysis.accessors &&
367-
context.state.analysis.runes
366+
!context.state.analysis.accessors
368367
) {
369368
// Handle $$props.something use-cases
370369
if (!added_props) {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
compileOptions: { dev: true }, // tests `@validate_store` code generation
5+
6+
html: `<button>clicks:\n0</button>`
7+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
import {writable} from 'svelte/store'
3+
let store = writable(0)
4+
</script>
5+
6+
<button onclick={() => {
7+
if(store && $store){
8+
9+
}
10+
}}>
11+
clicks: {$store}
12+
</button>

0 commit comments

Comments
 (0)