Skip to content

Commit

Permalink
fix: use coarse-grained updates for derived expressions in legacy mode (
Browse files Browse the repository at this point in the history
#11652)

fixes #11648
Also deduplicates the code a bit
  • Loading branch information
dummdidumm committed May 16, 2024
1 parent 54083fb commit c2f75dc
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/fresh-beds-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte": patch
---

fix: use coarse-grained updates for derived expressions passed to props in legacy mode
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,15 @@ function collect_parent_each_blocks(context) {
);
}

/**
* Svelte legacy mode should use safe equals in most places, runes mode shouldn't
* @param {import('../types.js').ComponentClientTransformState} state
* @param {import('estree').Expression} arg
*/
function create_derived(state, arg) {
return b.call(state.analysis.runes ? '$.derived' : '$.derived_safe_equal', arg);
}

/**
* @param {import('#compiler').Component | import('#compiler').SvelteComponent | import('#compiler').SvelteSelf} node
* @param {string} component_name
Expand Down Expand Up @@ -745,7 +754,7 @@ function serialize_inline_component(node, component_name, context) {

if (should_wrap_in_derived) {
const id = b.id(context.state.scope.generate(attribute.name));
context.state.init.push(b.var(id, b.call('$.derived', b.thunk(value))));
context.state.init.push(b.var(id, create_derived(context.state, b.thunk(value))));
arg = b.call('$.get', id);
}

Expand Down Expand Up @@ -1649,9 +1658,8 @@ function serialize_template_literal(values, visit, state) {
state.init.push(
b.const(
id,
b.call(
// In runes mode, we want things to be fine-grained - but not in legacy mode
state.analysis.runes ? '$.derived' : '$.derived_safe_equal',
create_derived(
state,
b.thunk(/** @type {import('estree').Expression} */ (visit(node.expression)))
)
)
Expand Down Expand Up @@ -1701,9 +1709,8 @@ export const template_visitors = {
state.init.push(
b.const(
declaration.id,
b.call(
// In runes mode, we want things to be fine-grained - but not in legacy mode
state.analysis.runes ? '$.derived' : '$.derived_safe_equal',
create_derived(
state,
b.thunk(/** @type {import('estree').Expression} */ (visit(declaration.init)))
)
)
Expand Down Expand Up @@ -1738,10 +1745,7 @@ export const template_visitors = {
])
);

state.init.push(
// In runes mode, we want things to be fine-grained - but not in legacy mode
b.const(tmp, b.call(state.analysis.runes ? '$.derived' : '$.derived_safe_equal', fn))
);
state.init.push(b.const(tmp, create_derived(state, fn)));

// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
Expand Down Expand Up @@ -2995,12 +2999,7 @@ export const template_visitors = {
const name = node.expression === null ? node.name : node.expression.name;
return b.const(
name,
b.call(
// in legacy mode, sources can be mutated but they're not fine-grained.
// Using the safe-equal derived version ensures the slot is still updated
state.analysis.runes ? '$.derived' : '$.derived_safe_equal',
b.thunk(b.member(b.id('$$slotProps'), b.id(node.name)))
)
create_derived(state, b.thunk(b.member(b.id('$$slotProps'), b.id(node.name))))
);
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
export let x;
</script>

child: {x.y}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test } from '../../test';

export default test({
html: `child: 0 parent: 0 <button>inc x</button>`,

async test({ assert, target }) {
await target.querySelector('button')?.click();
assert.htmlEqual(target.innerHTML, `child: 1 parent: 1 <button>inc x</button>`);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script>
import Child from "./Child.svelte";
let x;
$: if (!x) x = {y:0};
</script>

<Child x={x ?? {}} />

parent: {x.y}
<button on:click={() => x.y++}>inc x</button>

0 comments on commit c2f75dc

Please sign in to comment.