From fe4a56b0a8b065777c4f01dab63e4fbd260ef758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gautier=20Ben=20A=C3=AFm?= <48261497+GauBen@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:06:15 +0200 Subject: [PATCH] fix: avoid double-calling a derived reference when destructuring (#18668) Hi! This PR fixes #18666 ### Before submitting the PR, please make sure you do the following - [x] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs - [x] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`. - [x] This message body should clearly illustrate what problems it solves. - [x] Ideally, include a test that fails without this PR but passes with it. - [x] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`). ### Tests and linting - [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` --- .changeset/nervous-dolls-clean.md | 5 +++++ .../3-transform/server/visitors/VariableDeclaration.js | 6 ++++-- .../samples/derived-destructured-from-derived/_config.js | 5 +++++ .../samples/derived-destructured-from-derived/main.svelte | 8 ++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .changeset/nervous-dolls-clean.md create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/main.svelte diff --git a/.changeset/nervous-dolls-clean.md b/.changeset/nervous-dolls-clean.md new file mode 100644 index 0000000000..5b31bdd3c7 --- /dev/null +++ b/.changeset/nervous-dolls-clean.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: avoid double-calling a derived reference when destructuring `$derived` of another `$derived` during server-side rendering diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index 2c7b14afa5..108f65a884 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -102,9 +102,11 @@ export function VariableDeclaration(node, context) { } else { const call = /** @type {CallExpression} */ (declarator.init); - let rhs = value; + // - cannot be a SpreadElement because refused during analysis + // - use args[0] rather than value to avoid visiting twice (above in const value = ... and below in for-ofs) + let rhs = /** @type {Expression} */ (call.arguments[0]); - if (rune !== '$derived' || call.arguments[0].type !== 'Identifier') { + if (rune === '$derived.by' || call.arguments[0].type !== 'Identifier') { const id = b.id(context.state.scope.generate('$$d')); rhs = b.call(id); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/_config.js new file mode 100644 index 0000000000..a36c2adf7d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `` +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/main.svelte new file mode 100644 index 0000000000..b1882243f4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-destructured-from-derived/main.svelte @@ -0,0 +1,8 @@ + + + +