diff --git a/.changeset/good-plums-type.md b/.changeset/good-plums-type.md new file mode 100644 index 000000000000..9a1d8965f395 --- /dev/null +++ b/.changeset/good-plums-type.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: set correct component context when rendering snippets diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 64d35f398930..c7b92d4af0ed 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -384,6 +384,7 @@ export function analyze_component(root, source, options) { reactive_statements: new Map(), binding_groups: new Map(), slot_names: new Map(), + top_level_snippets: [], css: { ast: root.css, hash: root.css diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 6e9c17faab98..5259712266c2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -354,6 +354,7 @@ export function client_component(source, analysis, options) { ...store_setup, ...legacy_reactive_declarations, ...group_binding_declarations, + ...analysis.top_level_snippets, .../** @type {import('estree').Statement[]} */ (instance.body), analysis.runes || !analysis.needs_context ? b.empty : b.stmt(b.call('$.init')), .../** @type {import('estree').Statement[]} */ (template.body) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index c508414f72ce..eca72e16b8be 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -835,10 +835,7 @@ function serialize_inline_component(node, component_name, context) { if (slot_name === 'default') { push_prop( - b.init( - 'children', - context.state.options.dev ? b.call('$.add_snippet_symbol', slot_fn) : slot_fn - ) + b.init('children', context.state.options.dev ? b.call('$.wrap_snippet', slot_fn) : slot_fn) ); } else { serialized_slots.push(b.init(slot_name, slot_fn)); @@ -2566,16 +2563,20 @@ export const template_visitors = { .../** @type {import('estree').BlockStatement} */ (context.visit(node.body)).body ]); - const path = context.path; - // If we're top-level, then we can create a function for the snippet so that it can be referenced - // in the props declaration (default value pattern). - if (path.length === 1 && path[0].type === 'Fragment') { - context.state.init.push(b.function_declaration(node.expression, args, body)); - } else { - context.state.init.push(b.const(node.expression, b.arrow(args, body))); - } + /** @type {import('estree').Expression} */ + let snippet = b.arrow(args, body); + if (context.state.options.dev) { - context.state.init.push(b.stmt(b.call('$.add_snippet_symbol', node.expression))); + snippet = b.call('$.wrap_snippet', snippet); + } + + const declaration = b.var(node.expression, snippet); + + // Top-level snippets are hoisted so they can be referenced in the ` + + diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/Outer.svelte b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/Outer.svelte new file mode 100644 index 000000000000..a49a7392846a --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/Outer.svelte @@ -0,0 +1,5 @@ + + +{@render children?.()} diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/_config.js b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/_config.js new file mode 100644 index 000000000000..8f9cf55514ab --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ``, + + compileOptions: { + dev: true + }, + + warnings: [] +}); diff --git a/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/main.svelte b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/main.svelte new file mode 100644 index 000000000000..bbf7026cefde --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/non-local-mutation-with-binding-4/main.svelte @@ -0,0 +1,10 @@ + + + + + diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js index 4f78c872b526..87f74847c905 100644 --- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js @@ -6,16 +6,15 @@ var root_1 = $.template(`Something`, 1); var root = $.template(` `, 1); export default function Bind_component_snippet($$anchor) { - let value = $.source(''); - const _snippet = snippet; - var fragment_1 = root(); - - function snippet($$anchor) { + var snippet = ($$anchor) => { var fragment = root_1(); $.append($$anchor, fragment); - } + }; + let value = $.source(''); + const _snippet = snippet; + var fragment_1 = root(); var node = $.first_child(fragment_1); TextInput(node, {