diff --git a/.changeset/smooth-windows-explain.md b/.changeset/smooth-windows-explain.md new file mode 100644 index 0000000000..82f86945ea --- /dev/null +++ b/.changeset/smooth-windows-explain.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure event handlers referencing $host are not hoisted diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js index 85dfc6c67e..05ba0d486f 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js @@ -155,8 +155,8 @@ function get_delegated_event(event_name, handler, context) { const visited_references = new Set(); const scope = target_function.metadata.scope; for (const [reference] of scope.references) { - // Bail out if the arguments keyword is used - if (reference === 'arguments') return unhoisted; + // Bail out if the arguments keyword is used or $host is referenced + if (reference === 'arguments' || reference === '$host') return unhoisted; // Bail out if references a store subscription if (scope.get(`$${reference}`)?.kind === 'store_sub') return unhoisted; diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js index 0c2625dc20..bf09e864fa 100644 --- a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/_config.js @@ -14,11 +14,13 @@ export default test({ await tick(); - el.shadowRoot.querySelector('button').click(); - assert.deepEqual(events, ['greeting', 'hello']); + el.shadowRoot.querySelectorAll('button')[0].click(); + el.shadowRoot.querySelectorAll('button')[1].click(); + assert.deepEqual(events, ['greeting', 'hello', 'greeting', 'welcome']); el.removeEventListener('greeting', handle_evt); - el.shadowRoot.querySelector('button').click(); - assert.deepEqual(events, ['greeting', 'hello']); + el.shadowRoot.querySelectorAll('button')[0].click(); + el.shadowRoot.querySelectorAll('button')[1].click(); + assert.deepEqual(events, ['greeting', 'hello', 'greeting', 'welcome']); } }); diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte index 080e7a2740..2eddf77e9b 100644 --- a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte +++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune/main.svelte @@ -4,6 +4,11 @@ function greet(greeting) { $host().dispatchEvent(new CustomEvent('greeting', { detail: greeting })) } + + function welcome() { + $host().dispatchEvent(new CustomEvent('greeting', { detail: 'welcome' })) + } +