diff --git a/.changeset/odd-jobs-taste.md b/.changeset/odd-jobs-taste.md new file mode 100644 index 000000000000..5e2b097815e9 --- /dev/null +++ b/.changeset/odd-jobs-taste.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: wrap props in deriveds more conservatively in legacy mode diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 5a0adfc40c25..a62666e18072 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -1263,8 +1263,9 @@ const common_visitors = { }, CallExpression(node, context) { if ( - context.state.expression?.type === 'ExpressionTag' || - (context.state.expression?.type === 'SpreadAttribute' && !is_known_safe_call(node, context)) + (context.state.expression?.type === 'ExpressionTag' || + context.state.expression?.type === 'SpreadAttribute') && + !is_known_safe_call(node, context) ) { context.state.expression.metadata.contains_call_expression = true; } 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 082a6c4dee41..a2a5084dfa1a 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 @@ -719,11 +719,15 @@ function serialize_inline_component(node, component_name, context) { const should_wrap_in_derived = Array.isArray(attribute.value) && attribute.value.some((n) => { - return ( - n.type === 'ExpressionTag' && - n.expression.type !== 'Identifier' && - n.expression.type !== 'MemberExpression' - ); + if (n.type !== 'ExpressionTag') return false; + if (n.expression.type === 'Identifier' || n.expression.type === 'Literal') return false; + + if (n.expression.type === 'MemberExpression' && context.state.analysis.runes) { + // in legacy mode, `foo={bar.baz}` is wrapped in derived to preserve old behaviour. + return false; + } + + return true; }); if (should_wrap_in_derived) { diff --git a/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/Child.svelte new file mode 100644 index 000000000000..3b4b540cc958 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/Child.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/_config.js new file mode 100644 index 000000000000..b1bb9e5d3c73 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, logs, target }) { + assert.deepEqual(logs, ['x', 42]); + + const btn = target.querySelector('button'); + flushSync(() => btn?.click()); + + assert.deepEqual(logs, ['x', 42]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/main.svelte new file mode 100644 index 000000000000..584555717328 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-prop-derived/main.svelte @@ -0,0 +1,9 @@ + + + + +