diff --git a/.changeset/good-steaks-rhyme.md b/.changeset/good-steaks-rhyme.md new file mode 100644 index 0000000000..31ff7b390e --- /dev/null +++ b/.changeset/good-steaks-rhyme.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: update expressions on server deriveds diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/UpdateExpression.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/UpdateExpression.js index 8a2f874e22..7438ffddce 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/UpdateExpression.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/UpdateExpression.js @@ -9,17 +9,26 @@ import * as b from '#compiler/builders'; export function UpdateExpression(node, context) { const argument = node.argument; - if ( - argument.type === 'Identifier' && - context.state.scope.get(argument.name)?.kind === 'store_sub' - ) { - return b.call( - node.prefix ? '$.update_store_pre' : '$.update_store', - b.assignment('??=', b.id('$$store_subs'), b.object([])), - b.literal(argument.name), - b.id(argument.name.slice(1)), - node.operator === '--' && b.literal(-1) - ); + if (argument.type === 'Identifier') { + const binding = context.state.scope.get(argument.name); + + if (binding?.kind === 'store_sub') { + return b.call( + node.prefix ? '$.update_store_pre' : '$.update_store', + b.assignment('??=', b.id('$$store_subs'), b.object([])), + b.literal(argument.name), + b.id(argument.name.slice(1)), + node.operator === '--' && b.literal(-1) + ); + } + + if (binding?.kind === 'derived') { + return b.call( + node.prefix ? '$.update_derived_pre' : '$.update_derived', + binding.node, + node.operator === '--' && b.literal(-1) + ); + } } return context.next(); diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index f725a9c295..70f1f6dab8 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -504,6 +504,35 @@ export function derived(fn) { }; } +/** + * @template {number | bigint} T + * @param {(value?: T) => T} derived + * @param {1 | -1} [d] + * @returns {T} + */ +export function update_derived(derived, d = 1) { + const value = derived(); + let increase = typeof value === 'bigint' ? BigInt(d) : d; + // for some reason TS is mad even if T is always number or bigint + derived(value + /** @type {*} */ (increase)); + return value; +} + +/** + * @template {number | bigint} T + * @param {(value?: T) => T} derived + * @param {1 | -1} [d] + * @returns {T} + */ +export function update_derived_pre(derived, d = 1) { + const old_value = derived(); + let increase = typeof old_value === 'bigint' ? BigInt(d) : d; + // for some reason TS is mad even if T is always number or bigint + const value = old_value + /** @type {*} */ (increase); + derived(value); + return value; +} + /** * @template T * @param {()=>T} fn diff --git a/packages/svelte/tests/runtime-runes/samples/derived-update-server/_config.js b/packages/svelte/tests/runtime-runes/samples/derived-update-server/_config.js new file mode 100644 index 0000000000..b819023a7c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-update-server/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + mode: ['async-server', 'server'], + html: '
postfix: 0, postfix_minus: 1, prefix: 1, prefix_minus: 0, count: 0
postfix_n: 0, postfix_minus_n: 1, prefix_n: 1, prefix_minus_n: 0, count_n: 0
' +}); diff --git a/packages/svelte/tests/runtime-runes/samples/derived-update-server/main.svelte b/packages/svelte/tests/runtime-runes/samples/derived-update-server/main.svelte new file mode 100644 index 0000000000..04c5ee1b8c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/derived-update-server/main.svelte @@ -0,0 +1,17 @@ + + +postfix: {postfix}, postfix_minus: {postfix_minus}, prefix: {prefix}, prefix_minus: {prefix_minus}, count: {count}
+postfix_n: {postfix_n}, postfix_minus_n: {postfix_minus_n}, prefix_n: {prefix_n}, prefix_minus_n: {prefix_minus_n}, count_n: {count_n}
+