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 @@
+
+
-
+
+
+
+
+
+