diff --git a/.changeset/mighty-balloons-rush.md b/.changeset/mighty-balloons-rush.md new file mode 100644 index 0000000000..ce8c09ca55 --- /dev/null +++ b/.changeset/mighty-balloons-rush.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: allow async destructured deriveds diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 19a7de5715..0998dc4778 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -171,11 +171,14 @@ export function VariableDeclaration(node, context) { context.state.transform[id.name] = { read: get_value }; const expression = /** @type {Expression} */ (context.visit(b.thunk(value))); - const call = b.call('$.derived', expression); - return b.declarator( - id, - dev ? b.call('$.tag', call, b.literal('[$state iterable]')) : call - ); + let call = b.call('$.derived', expression); + + if (dev) { + const label = `[$state ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; + call = b.call('$.tag', call, b.literal(label)); + } + + return b.declarator(id, call); }), ...paths.map((path) => { const value = /** @type {Expression} */ (context.visit(path.expression)); @@ -228,19 +231,37 @@ export function VariableDeclaration(node, context) { } } else { const init = /** @type {CallExpression} */ (declarator.init); + let expression = /** @type {Expression} */ ( + context.visit(value, { + ...context.state, + in_derived: rune === '$derived' + }) + ); let rhs = value; if (rune !== '$derived' || init.arguments[0].type !== 'Identifier') { const id = b.id(context.state.scope.generate('$$d')); + let call = b.call('$.derived', rune === '$derived' ? b.thunk(expression) : expression); + rhs = b.call('$.get', id); - let expression = /** @type {Expression} */ (context.visit(value)); - if (rune === '$derived') expression = b.thunk(expression); - const call = b.call('$.derived', expression); - declarations.push( - b.declarator(id, dev ? b.call('$.tag', call, b.literal('[$derived iterable]')) : call) - ); + if (is_async) { + const location = dev && !is_ignored(init, 'await_waterfall') && locate_node(init); + call = b.call( + '$.async_derived', + b.thunk(expression, true), + location ? b.literal(location) : undefined + ); + call = b.call(b.await(b.call('$.save', call))); + } + + if (dev) { + const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; + call = b.call('$.tag', call, b.literal(label)); + } + + declarations.push(b.declarator(id, call)); } const { inserts, paths } = extract_paths(declarator.id, rhs); @@ -250,10 +271,14 @@ export function VariableDeclaration(node, context) { context.state.transform[id.name] = { read: get_value }; const expression = /** @type {Expression} */ (context.visit(b.thunk(value))); - const call = b.call('$.derived', expression); - declarations.push( - b.declarator(id, dev ? b.call('$.tag', call, b.literal('[$derived iterable]')) : call) - ); + let call = b.call('$.derived', expression); + + if (dev) { + const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; + call = b.call('$.tag', call, b.literal(label)); + } + + declarations.push(b.declarator(id, call)); } for (const path of paths) { diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/Child.svelte new file mode 100644 index 0000000000..39112b12a7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/Child.svelte @@ -0,0 +1,13 @@ + + + + +
{count} ** 2 = {squared}
+{count} ** 3 = {cubed}
diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/_config.js b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/_config.js new file mode 100644 index 0000000000..d444e8e1d9 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/_config.js @@ -0,0 +1,31 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await tick(); + + const [increment] = target.querySelectorAll('button'); + + assert.htmlEqual( + target.innerHTML, + ` + +1 ** 2 = 1
+1 ** 3 = 1
+ ` + ); + + increment.click(); + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` + +2 ** 2 = 4
+2 ** 3 = 8
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/main.svelte new file mode 100644 index 0000000000..c5d8a12a78 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-derived-destructured/main.svelte @@ -0,0 +1,11 @@ + + +pending
+ {/snippet} +