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`
pull/18673/head
Gautier Ben Aïm 4 weeks ago committed by GitHub
parent 384ee73aa2
commit fe4a56b0a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: avoid double-calling a derived reference when destructuring `$derived` of another `$derived` during server-side rendering

@ -102,9 +102,11 @@ export function VariableDeclaration(node, context) {
} else { } else {
const call = /** @type {CallExpression} */ (declarator.init); 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')); const id = b.id(context.state.scope.generate('$$d'));
rhs = b.call(id); rhs = b.call(id);

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
html: `<button>3</button>`
});

@ -0,0 +1,8 @@
<script>
let name = $state('foo');
const foo = $derived(name);
const { length } = $derived(foo);
</script>
<!-- only needed to prevent constant folding, never run -->
<button onclick={() => (name = 'longer')}>{length}</button>
Loading…
Cancel
Save