diff --git a/.changeset/bright-papayas-sneeze.md b/.changeset/bright-papayas-sneeze.md new file mode 100644 index 000000000000..8587aebc6681 --- /dev/null +++ b/.changeset/bright-papayas-sneeze.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: do not treat reassigned synthetic binds as state in runes mode diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 36d8145145c7..9e4f72a66d7a 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -276,6 +276,8 @@ export function analyze_component(root, source, options) { /** @type {Template} */ const template = { ast: root.fragment, scope, scopes }; + let synthetic_stores_legacy_check = []; + // create synthetic bindings for store subscriptions for (const [name, references] of module.scope.references) { if (name[0] !== '$' || RESERVED.includes(name)) continue; @@ -351,16 +353,21 @@ export function analyze_component(root, source, options) { } } - // if we are creating a synthetic binding for a let declaration we should also declare - // the declaration as state in case it's reassigned - if ( - declaration !== null && - declaration.kind === 'normal' && - declaration.declaration_kind === 'let' && - declaration.reassigned - ) { - declaration.kind = 'state'; - } + // we push to the array because at this moment in time we can't be sure if we are in legacy + // mode yet because we are still changing the module scope + synthetic_stores_legacy_check.push(() => { + // if we are creating a synthetic binding for a let declaration we should also declare + // the declaration as state in case it's reassigned and we are not in runes mode (the function will + // not be called if we are not in runes mode, that's why there's no !runes check here) + if ( + declaration !== null && + declaration.kind === 'normal' && + declaration.declaration_kind === 'let' && + declaration.reassigned + ) { + declaration.kind = 'state'; + } + }); const binding = instance.scope.declare(b.id(name), 'store_sub', 'synthetic'); binding.references = references; @@ -373,6 +380,12 @@ export function analyze_component(root, source, options) { const runes = options.runes ?? Array.from(module.scope.references.keys()).some(is_rune); + if (!runes) { + for (let check of synthetic_stores_legacy_check) { + check(); + } + } + if (runes && root.module) { const context = root.module.attributes.find((attribute) => attribute.name === 'context'); if (context) { diff --git a/packages/svelte/tests/runtime-runes/samples/reassigned-store-not-state/_config.js b/packages/svelte/tests/runtime-runes/samples/reassigned-store-not-state/_config.js new file mode 100644 index 000000000000..7091b344793d --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/reassigned-store-not-state/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ logs, assert }) { + assert.deepEqual(logs, ['world']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/reassigned-store-not-state/main.svelte b/packages/svelte/tests/runtime-runes/samples/reassigned-store-not-state/main.svelte new file mode 100644 index 000000000000..95da95901275 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/reassigned-store-not-state/main.svelte @@ -0,0 +1,13 @@ +