Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/thick-pans-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: don't hoist listeners that access non hoistable snippets
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @import { ArrowFunctionExpression, Expression, FunctionDeclaration, FunctionExpression } from 'estree' */
/** @import { AST, DelegatedEvent } from '#compiler' */
/** @import { Context } from '../types' */
import exp from 'node:constants';
import { cannot_be_set_statically, is_capture_event, is_delegated } from '../../../../utils.js';
import {
get_attribute_chunks,
Expand Down Expand Up @@ -183,6 +184,15 @@ function get_delegated_event(event_name, handler, context) {
const binding = scope.get(reference);
const local_binding = context.state.scope.get(reference);

// if the function access a snippet that can't be hoisted we bail out
if (
local_binding !== null &&
local_binding.initial?.type === 'SnippetBlock' &&
!local_binding.initial.metadata.can_hoist
) {
return unhoisted;
}

// If we are referencing a binding that is shadowed in another scope then bail out.
if (local_binding !== null && binding !== null && local_binding.node !== binding.node) {
return unhoisted;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
async test({ assert, target, errors }) {
const button = target.querySelector('button');
flushSync(() => {
button?.click();
});
assert.deepEqual(errors, []);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script>
const log = () => {
console.log(snip);
}
let x = $state(0);
</script>

<button onclick={log}></button>

{#snippet snip()}
snippet {x}
{/snippet}