diff --git a/.changeset/nervous-adults-sell.md b/.changeset/nervous-adults-sell.md
new file mode 100644
index 0000000000..a7bad9bda8
--- /dev/null
+++ b/.changeset/nervous-adults-sell.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure `$store` reads are properly transformed
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js
index dc30255a1a..f3f3808594 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js
@@ -42,11 +42,17 @@ export function Program(_, context) {
for (const [name, binding] of context.state.scope.declarations) {
if (binding.kind === 'store_sub') {
- const store = /** @type {Expression} */ (context.visit(b.id(name.slice(1))));
+ // read lazily, so that transforms added later are still applied
+ /** @type {Expression} */
+ let cached;
+
+ const get_store = () => {
+ return (cached ??= /** @type {Expression} */ (context.visit(b.id(name.slice(1)))));
+ };
context.state.transform[name] = {
read: b.call,
- assign: (_, value) => b.call('$.store_set', store, value),
+ assign: (_, value) => b.call('$.store_set', get_store(), value),
mutate: (node, mutation) => {
// We need to untrack the store read, for consistency with Svelte 4
const untracked = b.call('$.untrack', node);
@@ -70,7 +76,7 @@ export function Program(_, context) {
return b.call(
'$.store_mutate',
- store,
+ get_store(),
b.assignment(
mutation.operator,
/** @type {MemberExpression} */ (
diff --git a/packages/svelte/tests/runtime-runes/samples/store-from-derived/_config.js b/packages/svelte/tests/runtime-runes/samples/store-from-derived/_config.js
new file mode 100644
index 0000000000..8cb3fd9cae
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/store-from-derived/_config.js
@@ -0,0 +1,11 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ html: ``,
+ test({ assert, target }) {
+ target.querySelector('button')?.click();
+ flushSync();
+ assert.htmlEqual(target.innerHTML, ``);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/store-from-derived/main.svelte b/packages/svelte/tests/runtime-runes/samples/store-from-derived/main.svelte
new file mode 100644
index 0000000000..728544e664
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/store-from-derived/main.svelte
@@ -0,0 +1,7 @@
+
+
+