From e2dcdc2887f02e4a969d6c576e0344410b4059a5 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Thu, 7 Dec 2023 12:30:02 +0000 Subject: [PATCH] fix: ensure computed props are wrapped in derived (#9835) --- .changeset/sharp-tomatoes-learn.md | 5 +++++ .../3-transform/client/visitors/template.js | 13 ++++++++++--- .../samples/props-derived-2/Item.svelte | 10 ++++++++++ .../samples/props-derived-2/_config.js | 19 +++++++++++++++++++ .../samples/props-derived-2/log.js | 2 ++ .../samples/props-derived-2/main.svelte | 11 +++++++++++ 6 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 .changeset/sharp-tomatoes-learn.md create mode 100644 packages/svelte/tests/runtime-runes/samples/props-derived-2/Item.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-derived-2/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/props-derived-2/log.js create mode 100644 packages/svelte/tests/runtime-runes/samples/props-derived-2/main.svelte diff --git a/.changeset/sharp-tomatoes-learn.md b/.changeset/sharp-tomatoes-learn.md new file mode 100644 index 0000000000..03f5930c23 --- /dev/null +++ b/.changeset/sharp-tomatoes-learn.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure computed props are wrapped in derived 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 bde6d1adf9..4ec77b167d 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 @@ -782,13 +782,20 @@ function serialize_inline_component(node, component_name, context) { if (attribute.metadata.dynamic) { let arg = value; - const contains_call_expression = + // When we have a non-simple computation, anything other than an Identifier or Member expression, + // then there's a good chance it needs to be memoized to avoid over-firing when read within the + // child component. + const should_wrap_in_derived = Array.isArray(attribute.value) && attribute.value.some((n) => { - return n.type === 'ExpressionTag' && n.metadata.contains_call_expression; + return ( + n.type === 'ExpressionTag' && + n.expression.type !== 'Identifier' && + n.expression.type !== 'MemberExpression' + ); }); - if (contains_call_expression) { + if (should_wrap_in_derived) { const id = b.id(context.state.scope.generate(attribute.name)); context.state.init.push(b.var(id, b.call('$.derived', b.thunk(value)))); arg = b.call('$.get', id); diff --git a/packages/svelte/tests/runtime-runes/samples/props-derived-2/Item.svelte b/packages/svelte/tests/runtime-runes/samples/props-derived-2/Item.svelte new file mode 100644 index 0000000000..1c2c6e7182 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-derived-2/Item.svelte @@ -0,0 +1,10 @@ + + +

Item is {active ? 'active' : 'inactive'}

diff --git a/packages/svelte/tests/runtime-runes/samples/props-derived-2/_config.js b/packages/svelte/tests/runtime-runes/samples/props-derived-2/_config.js new file mode 100644 index 0000000000..32b526c9a8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-derived-2/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; +import { log } from './log.js'; + +export default test({ + before_test() { + log.length = 0; + }, + + async test({ assert, target }) { + log.length = 0; + + const input = /** @type {HTMLInputElement} */ (target.querySelector('input')); + input.value = '1'; + flushSync(() => input.dispatchEvent(new window.Event('input'))); + + assert.deepEqual(log, ['active changed', false, 'active changed', true]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-derived-2/log.js b/packages/svelte/tests/runtime-runes/samples/props-derived-2/log.js new file mode 100644 index 0000000000..d3df521f4d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-derived-2/log.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const log = []; diff --git a/packages/svelte/tests/runtime-runes/samples/props-derived-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-derived-2/main.svelte new file mode 100644 index 0000000000..04f3834679 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-derived-2/main.svelte @@ -0,0 +1,11 @@ + + + + + + + +