fix: bail out of event hoisting when referencing store subscriptions (#12301)

pull/12304/head
Dominic Gannaway 3 months ago committed by GitHub
parent 521988c53e
commit 80263770f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: bail out of event hoisting when referencing store subscriptions

@ -166,25 +166,20 @@ function get_delegated_event(event_name, handler, context) {
} }
// If we can't find a function, bail-out // If we can't find a function, bail-out
if (target_function == null) { if (target_function == null) return non_hoistable;
return non_hoistable;
}
// If the function is marked as non-hoistable, bail-out // If the function is marked as non-hoistable, bail-out
if (target_function.metadata.hoistable === 'impossible') { if (target_function.metadata.hoistable === 'impossible') return non_hoistable;
return non_hoistable;
}
// If the function has more than one arg, then bail-out // If the function has more than one arg, then bail-out
if (target_function.params.length > 1) { if (target_function.params.length > 1) return non_hoistable;
return non_hoistable;
}
const visited_references = new Set(); const visited_references = new Set();
const scope = target_function.metadata.scope; const scope = target_function.metadata.scope;
for (const [reference] of scope.references) { for (const [reference] of scope.references) {
// Bail-out if the arguments keyword is used // Bail-out if the arguments keyword is used
if (reference === 'arguments') { if (reference === 'arguments') return non_hoistable;
return non_hoistable; // Bail-out if references a store subscription
} if (scope.get(`$${reference}`)?.kind === 'store_sub') return non_hoistable;
const binding = scope.get(reference); const binding = scope.get(reference);
const local_binding = context.state.scope.get(reference); const local_binding = context.state.scope.get(reference);
@ -203,9 +198,7 @@ function get_delegated_event(event_name, handler, context) {
} }
// If we reference the index within an each block, then bail-out. // If we reference the index within an each block, then bail-out.
if (binding !== null && binding.initial?.type === 'EachBlock') { if (binding !== null && binding.initial?.type === 'EachBlock') return non_hoistable;
return non_hoistable;
}
if ( if (
binding !== null && binding !== null &&

@ -0,0 +1,26 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
test({ assert, target }) {
const [b1, b2] = target.querySelectorAll('button');
b1.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
'<button>set new store</button><button>incr</button><pre>0</pre>'
);
b2.click();
b2.click();
b2.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
'<button>set new store</button><button>incr</button><pre>3</pre>'
);
}
});

@ -0,0 +1,17 @@
<script>
import { writable } from 'svelte/store';
let store = $state();
function setStore() {
store = writable(0, () => {
console.log('start');
return () => console.log('stop');
});
}
</script>
<button onclick={setStore}>set new store</button>
<button onclick={() => $store++}>incr</button>
<pre>{$store}</pre>
Loading…
Cancel
Save