diff --git a/.changeset/many-trees-fix.md b/.changeset/many-trees-fix.md new file mode 100644 index 0000000000..1eaf163104 --- /dev/null +++ b/.changeset/many-trees-fix.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +fix: don't hoist function when already referenced in module scope diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 471b432b05..0af7b5430d 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -94,6 +94,11 @@ function get_delegated_event(event_name, handler, context) { } else if (handler.type === 'Identifier') { binding = context.state.scope.get(handler.name); + if (context.state.analysis.module.scope.references.has(handler.name)) { + // If a binding with the same name is referenced in the module scope (even if not declared there), bail-out + return non_hoistable; + } + if (binding != null) { for (const { path } of binding.references) { const parent = path.at(-1); diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js index ce79b44f49..0d7d885e59 100644 --- a/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/_config.js @@ -1,18 +1,25 @@ import { test } from '../../test'; -// Checks that event handlers are not hoisted when one of them is not delegateable export default test({ - html: ``, + html: ``, async test({ assert, target }) { - const [button] = target.querySelectorAll('button'); + const [btn1, btn2, btn3] = target.querySelectorAll('button'); - button.click(); + btn1.click(); await Promise.resolve(); - assert.htmlEqual(target.innerHTML, ''); + assert.htmlEqual(target.innerHTML, ''); - button.dispatchEvent(new MouseEvent('mouseenter')); + btn1.dispatchEvent(new MouseEvent('mouseenter')); await Promise.resolve(); - assert.htmlEqual(target.innerHTML, ''); + assert.htmlEqual(target.innerHTML, ''); + + btn2.click(); + await Promise.resolve(); + assert.htmlEqual(target.innerHTML, ''); + + btn3.click(); + await Promise.resolve(); + assert.htmlEqual(target.innerHTML, ''); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte index 6f8766411b..6f31e8aa58 100644 --- a/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/event-attribute-not-hoistable/main.svelte @@ -1,11 +1,36 @@ + + - + + + + + +