diff --git a/src/compile/Component.ts b/src/compile/Component.ts index a429db41f6..b73c961672 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -787,6 +787,10 @@ export default class Component { return `${name.slice(1)}.set(${name})` } + if (variable && !variable.referenced && !variable.is_reactive_dependency && !variable.export_name && !name.startsWith('$$')) { + return value || name; + } + if (value) { return `$$invalidate('${name}', ${value})`; } @@ -1118,8 +1122,9 @@ export default class Component { if (!assignee_nodes.has(identifier)) { const { name } = identifier; const owner = scope.find_owner(name); - const component_var = component.var_lookup.get(name); - const is_writable_or_mutated = component_var && (component_var.writable || component_var.mutated); + const variable = component.var_lookup.get(name); + if (variable) variable.is_reactive_dependency = true; + const is_writable_or_mutated = variable && (variable.writable || variable.mutated); if ( (!owner || owner === component.instance_scope) && (name[0] === '$' || is_writable_or_mutated) diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 0fd0d4b172..7942916dfb 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -204,8 +204,10 @@ export default function dom( if (variable && (variable.hoistable || variable.global || variable.module)) return; if (single && !(variable.subscribable && variable.reassigned)) { - code.prependRight(node.start, `$$invalidate('${name}', `); - code.appendLeft(node.end, `)`); + if (variable.referenced || variable.is_reactive_dependency || variable.export_name) { + code.prependRight(node.start, `$$invalidate('${name}', `); + code.appendLeft(node.end, `)`); + } } else { pending_assignments.add(name); } diff --git a/src/interfaces.ts b/src/interfaces.ts index 68fef7472e..dda698a0da 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -92,4 +92,5 @@ export interface Var { initialised?: boolean; hoistable?: boolean; subscribable?: boolean; + is_reactive_dependency: boolean; } \ No newline at end of file diff --git a/test/js/samples/reactive-values-non-topologically-ordered/expected.js b/test/js/samples/reactive-values-non-topologically-ordered/expected.js index 2f729362b0..b5e2b04f75 100644 --- a/test/js/samples/reactive-values-non-topologically-ordered/expected.js +++ b/test/js/samples/reactive-values-non-topologically-ordered/expected.js @@ -29,7 +29,7 @@ function instance($$self, $$props, $$invalidate) { $$self.$$.update = ($$dirty = { x: 1, b: 1 }) => { if ($$dirty.x) { $$invalidate('b', b = x); } - if ($$dirty.b) { $$invalidate('a', a = b); } + if ($$dirty.b) { a = b; } }; return { x }; diff --git a/test/js/samples/reactive-values-non-writable-dependencies/expected.js b/test/js/samples/reactive-values-non-writable-dependencies/expected.js index 62057cc6f0..8958f1ffbc 100644 --- a/test/js/samples/reactive-values-non-writable-dependencies/expected.js +++ b/test/js/samples/reactive-values-non-writable-dependencies/expected.js @@ -17,26 +17,25 @@ function create_fragment(ctx) { }; } -let a = 1; - -let b = 2; - function instance($$self, $$props, $$invalidate) { - + let { a = 1, b = 2 } = $$props; - let max; + $$self.$set = $$props => { + if ('a' in $$props) $$invalidate('a', a = $$props.a); + if ('b' in $$props) $$invalidate('b', b = $$props.b); + }; $$self.$$.update = ($$dirty = { a: 1, b: 1 }) => { - if ($$dirty.a || $$dirty.b) { $$invalidate('max', max = Math.max(a, b)); } + if ($$dirty.a || $$dirty.b) { console.log('max', Math.max(a, b)); } }; - return {}; + return { a, b }; } class Component extends SvelteComponent { constructor(options) { super(); - init(this, options, instance, create_fragment, safe_not_equal, []); + init(this, options, instance, create_fragment, safe_not_equal, ["a", "b"]); } } diff --git a/test/js/samples/reactive-values-non-writable-dependencies/input.svelte b/test/js/samples/reactive-values-non-writable-dependencies/input.svelte index 8e3397e40d..3fb70d5e8f 100644 --- a/test/js/samples/reactive-values-non-writable-dependencies/input.svelte +++ b/test/js/samples/reactive-values-non-writable-dependencies/input.svelte @@ -1,7 +1,6 @@ \ No newline at end of file diff --git a/test/js/samples/unreferenced-state-not-invalidated/expected.js b/test/js/samples/unreferenced-state-not-invalidated/expected.js new file mode 100644 index 0000000000..17b5638a84 --- /dev/null +++ b/test/js/samples/unreferenced-state-not-invalidated/expected.js @@ -0,0 +1,78 @@ +/* generated by Svelte vX.Y.Z */ +import { + SvelteComponent, + append, + detach, + element, + init, + insert, + noop, + safe_not_equal, + set_data, + text +} from "svelte/internal"; +import { onMount } from "svelte"; + +function create_fragment(ctx) { + var p, t; + + return { + c() { + p = element("p"); + t = text(ctx.y); + }, + + m(target, anchor) { + insert(target, p, anchor); + append(p, t); + }, + + p(changed, ctx) { + if (changed.y) { + set_data(t, ctx.y); + } + }, + + i: noop, + o: noop, + + d(detaching) { + if (detaching) { + detach(p); + } + } + }; +} + +function instance($$self, $$props, $$invalidate) { + let a, b, c; + + onMount(() => { + const interval = setInterval(() => { + $$invalidate('b', b += 1); + c += 1; + + console.log(b, c); + }, 1000); + + return () => clearInterval(interval); + }); + + let x, y; + + $$self.$$.update = ($$dirty = { a: 1, b: 1 }) => { + if ($$dirty.a) { x = a * 2; } + if ($$dirty.b) { $$invalidate('y', y = b * 2); } + }; + + return { y }; +} + +class Component extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, []); + } +} + +export default Component; \ No newline at end of file diff --git a/test/js/samples/unreferenced-state-not-invalidated/input.svelte b/test/js/samples/unreferenced-state-not-invalidated/input.svelte new file mode 100644 index 0000000000..fff60f181d --- /dev/null +++ b/test/js/samples/unreferenced-state-not-invalidated/input.svelte @@ -0,0 +1,21 @@ + + +

{y}

\ No newline at end of file diff --git a/test/runtime/samples/immutable-nested/Nested.svelte b/test/runtime/samples/immutable-nested/Nested.svelte index 45385e9b0b..acb0b480a4 100644 --- a/test/runtime/samples/immutable-nested/Nested.svelte +++ b/test/runtime/samples/immutable-nested/Nested.svelte @@ -1,7 +1,7 @@ -

Called {count} times.

\ No newline at end of file +

Called {count} times.

+

{foo.bar} {mounted}

\ No newline at end of file diff --git a/test/runtime/samples/immutable-nested/_config.js b/test/runtime/samples/immutable-nested/_config.js index e5c515fc78..da90b43727 100644 --- a/test/runtime/samples/immutable-nested/_config.js +++ b/test/runtime/samples/immutable-nested/_config.js @@ -1,16 +1,35 @@ export default { immutable: true, - html: `

Called 1 times.

`, + html: ` +
+

Called 1 times.

+

baz true

+
+ `, - ssrHtml: `

Called 0 times.

`, + ssrHtml: ` +
+

Called 0 times.

+

baz false

+
`, - test({ assert, component, target, window }) { + test({ assert, component, target }) { var nested = component.nested; - assert.htmlEqual(target.innerHTML, `

Called 1 times.

`); + assert.htmlEqual(target.innerHTML, ` +
+

Called 1 times.

+

baz true

+
+ `); nested.foo = nested.foo; - assert.htmlEqual(target.innerHTML, `

Called 1 times.

`); + assert.htmlEqual(target.innerHTML, ` +
+

Called 1 times.

+

baz true

+
+ `); } }; diff --git a/test/runtime/samples/immutable-nested/main.svelte b/test/runtime/samples/immutable-nested/main.svelte index e50055be0c..4ccf7008cd 100644 --- a/test/runtime/samples/immutable-nested/main.svelte +++ b/test/runtime/samples/immutable-nested/main.svelte @@ -5,5 +5,5 @@
- +