diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index a50a86e2f3..ffb2ec6f19 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -1,7 +1,7 @@ import { b, x, p } from 'code-red'; import Component from '../Component'; import Renderer from './Renderer'; -import { CompileOptions } from '../../interfaces'; +import { CompileOptions, Var } from '../../interfaces'; import { walk } from 'estree-walker'; import add_to_set from '../utils/add_to_set'; import { extract_names } from '../utils/scope'; @@ -167,27 +167,41 @@ export default function dom( `; } - capture_state = (uses_props || writable_props.length > 0) ? x` - () => { - return { ${component.vars.filter(prop => prop.writable).map(prop => p`${prop.name}`)} }; - } - ` : x` - () => { - return {}; - } - `; + // we need to filter out store subscriptions ($x) or $inject_state will try to call .set() on them, leading + // to a crash if store is not writable (and probably not intended behaviour to change store value) + const is_not_sub = (variable: Var) => variable.name.substr(0, 1) !== '$'; - const writable_vars = component.vars.filter(variable => !variable.module && variable.writable); - inject_state = (uses_props || writable_vars.length > 0) ? x` - ${$$props} => { - ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} - ${writable_vars.map(prop => b` - if ('${prop.name}' in $$props) ${component.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.name}`)}; - `)} - } - ` : x` - ${$$props} => {} - `; + const capturable_vars = component.vars.filter( + variable => !variable.module && variable.writable && is_not_sub(variable) + ); + + if (uses_props || capturable_vars.length > 0) { + + const capturable_props = writable_props.filter(is_not_sub); + + const local_vars = capturable_vars.filter(variable => !variable.export_name); + + const var_names = (variables: Var[]) => variables.map(prop => p`${prop.name}`); + + capture_state = x` + ({ props: $props = true, local: $local = true } = {}) => ({ + ...${x`$props && { ${var_names(capturable_props)} }`}, + ...${x`$local && { ${var_names(local_vars)} }`} + }) + `; + + inject_state = x` + ${$$props} => { + ${uses_props && component.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)} + ${capturable_vars.map(prop => b` + if ('${prop.name}' in $$props) ${component.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.name}`)}; + `)} + } + `; + } else { + capture_state = x`() => ({})`; + inject_state = x`() => {}`; + } } // instrument assignments diff --git a/test/js/samples/debug-empty/expected.js b/test/js/samples/debug-empty/expected.js index 2238fa3ecf..dc2748d431 100644 --- a/test/js/samples/debug-empty/expected.js +++ b/test/js/samples/debug-empty/expected.js @@ -78,9 +78,10 @@ function instance($$self, $$props, $$invalidate) { if ("name" in $$props) $$invalidate("name", name = $$props.name); }; - $$self.$capture_state = () => { - return { name }; - }; + $$self.$capture_state = ({ props: $props = true, local: $local = true } = {}) => ({ + ...$props && ({ name }), + ...$local && ({}) + }); $$self.$inject_state = $$props => { if ("name" in $$props) $$invalidate("name", name = $$props.name); @@ -118,4 +119,4 @@ class Component extends SvelteComponentDev { } } -export default Component; \ No newline at end of file +export default Component; diff --git a/test/js/samples/debug-foo-bar-baz-things/expected.js b/test/js/samples/debug-foo-bar-baz-things/expected.js index 4a8c145f5e..246e9d707f 100644 --- a/test/js/samples/debug-foo-bar-baz-things/expected.js +++ b/test/js/samples/debug-foo-bar-baz-things/expected.js @@ -175,9 +175,10 @@ function instance($$self, $$props, $$invalidate) { if ("baz" in $$props) $$invalidate("baz", baz = $$props.baz); }; - $$self.$capture_state = () => { - return { things, foo, bar, baz }; - }; + $$self.$capture_state = ({ props: $props = true, local: $local = true } = {}) => ({ + ...$props && ({ things, foo, bar, baz }), + ...$local && ({}) + }); $$self.$inject_state = $$props => { if ("things" in $$props) $$invalidate("things", things = $$props.things); @@ -254,4 +255,4 @@ class Component extends SvelteComponentDev { } } -export default Component; \ No newline at end of file +export default Component; diff --git a/test/js/samples/debug-foo/expected.js b/test/js/samples/debug-foo/expected.js index a91ed932c8..31a6b8542a 100644 --- a/test/js/samples/debug-foo/expected.js +++ b/test/js/samples/debug-foo/expected.js @@ -171,9 +171,10 @@ function instance($$self, $$props, $$invalidate) { if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; - $$self.$capture_state = () => { - return { things, foo }; - }; + $$self.$capture_state = ({ props: $props = true, local: $local = true } = {}) => ({ + ...$props && ({ things, foo }), + ...$local && ({}) + }); $$self.$inject_state = $$props => { if ("things" in $$props) $$invalidate("things", things = $$props.things); @@ -224,4 +225,4 @@ class Component extends SvelteComponentDev { } } -export default Component; \ No newline at end of file +export default Component; diff --git a/test/js/samples/debug-hoisted/expected.js b/test/js/samples/debug-hoisted/expected.js index b43e4a2d69..35a87e4122 100644 --- a/test/js/samples/debug-hoisted/expected.js +++ b/test/js/samples/debug-hoisted/expected.js @@ -49,9 +49,10 @@ let kobzol = 5; function instance($$self) { let obj = { x: 5 }; - $$self.$capture_state = () => { - return {}; - }; + $$self.$capture_state = ({ props: $props = true, local: $local = true } = {}) => ({ + ...$props && ({}), + ...$local && ({ obj, kobzol }) + }); $$self.$inject_state = $$props => { if ("obj" in $$props) $$invalidate("obj", obj = $$props.obj); @@ -75,4 +76,4 @@ class Component extends SvelteComponentDev { } } -export default Component; \ No newline at end of file +export default Component; diff --git a/test/js/samples/dev-warning-missing-data-computed/expected.js b/test/js/samples/dev-warning-missing-data-computed/expected.js index 27e0b797a2..92bc6b7027 100644 --- a/test/js/samples/dev-warning-missing-data-computed/expected.js +++ b/test/js/samples/dev-warning-missing-data-computed/expected.js @@ -75,9 +75,10 @@ function instance($$self, $$props, $$invalidate) { if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); }; - $$self.$capture_state = () => { - return { foo, bar }; - }; + $$self.$capture_state = ({ props: $props = true, local: $local = true } = {}) => ({ + ...$props && ({ foo }), + ...$local && ({ bar }) + }); $$self.$inject_state = $$props => { if ("foo" in $$props) $$invalidate("foo", foo = $$props.foo); @@ -122,4 +123,4 @@ class Component extends SvelteComponentDev { } } -export default Component; \ No newline at end of file +export default Component;