Skip to content

Commit af7f900

Browse files
authored
fix: ensure $store reads are properly transformed (#12952)
The backing store variable of a $store read could be a variable that itself needs a transformer, which is why we need to make accessing the reads lazy fixes #12859
1 parent 732dbf7 commit af7f900

File tree

4 files changed

+32
-3
lines changed

4 files changed

+32
-3
lines changed

.changeset/nervous-adults-sell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure `$store` reads are properly transformed

packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,17 @@ export function Program(_, context) {
4242

4343
for (const [name, binding] of context.state.scope.declarations) {
4444
if (binding.kind === 'store_sub') {
45-
const store = /** @type {Expression} */ (context.visit(b.id(name.slice(1))));
45+
// read lazily, so that transforms added later are still applied
46+
/** @type {Expression} */
47+
let cached;
48+
49+
const get_store = () => {
50+
return (cached ??= /** @type {Expression} */ (context.visit(b.id(name.slice(1)))));
51+
};
4652

4753
context.state.transform[name] = {
4854
read: b.call,
49-
assign: (_, value) => b.call('$.store_set', store, value),
55+
assign: (_, value) => b.call('$.store_set', get_store(), value),
5056
mutate: (node, mutation) => {
5157
// We need to untrack the store read, for consistency with Svelte 4
5258
const untracked = b.call('$.untrack', node);
@@ -70,7 +76,7 @@ export function Program(_, context) {
7076

7177
return b.call(
7278
'$.store_mutate',
73-
store,
79+
get_store(),
7480
b.assignment(
7581
mutation.operator,
7682
/** @type {MemberExpression} */ (
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<button>false</button>`,
6+
test({ assert, target }) {
7+
target.querySelector('button')?.click();
8+
flushSync();
9+
assert.htmlEqual(target.innerHTML, `<button>true</button>`);
10+
}
11+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
import { writable } from 'svelte/store';
3+
let data = { store: writable(false) };
4+
let { store } = $derived(data);
5+
</script>
6+
7+
<button onclick={() => ($store = true)}>{$store}</button>

0 commit comments

Comments
 (0)