diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 8a5d0af284..f8bb92e0e0 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -13,6 +13,7 @@ import get_object from '../../utils/get_object'; import { nodes_match } from '../../../utils/nodes_match'; import Block from '../../render_dom/Block'; import { INode } from '../interfaces'; +import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic'; const binary_operators: Record = { '**': 15, @@ -211,10 +212,7 @@ export default class Expression { if (name === '$$props') return true; const variable = this.component.var_lookup.get(name); - if (!variable) return false; - - if (variable.mutated || variable.reassigned) return true; // dynamic internal state - if (!variable.module && variable.writable && variable.export_name) return true; // writable props + return is_dynamic(variable); }); } diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index ece8abf3b0..9cff40ecbb 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -13,6 +13,7 @@ import create_debugging_comment from '../shared/create_debugging_comment'; import { get_context_merger } from '../shared/get_context_merger'; import EachBlock from '../../../nodes/EachBlock'; import TemplateScope from '../../../nodes/shared/TemplateScope'; +import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; export default class InlineComponentWrapper extends Wrapper { @@ -161,11 +162,7 @@ export default class InlineComponentWrapper extends Wrapper { const is_let = slot.scope.is_let(name); const variable = renderer.component.var_lookup.get(name); - if (is_let) fragment_dependencies.add(name); - - if (!variable) return; - if (variable.mutated || variable.reassigned) fragment_dependencies.add(name); - if (!variable.module && variable.writable && variable.export_name) fragment_dependencies.add(name); + if (is_let || is_dynamic(variable)) fragment_dependencies.add(name); }); }); diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 3376a797b8..4dd23277fb 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -9,6 +9,7 @@ import add_to_set from '../../utils/add_to_set'; import get_slot_data from '../../utils/get_slot_data'; import { stringify_props } from '../../utils/stringify_props'; import Expression from '../../nodes/shared/Expression'; +import is_dynamic from './shared/is_dynamic'; export default class SlotWrapper extends Wrapper { node: Slot; @@ -72,17 +73,27 @@ export default class SlotWrapper extends Wrapper { this.node.values.forEach(attribute => { attribute.chunks.forEach(chunk => { if ((chunk as Expression).dependencies) { - add_to_set(dependencies, (chunk as Expression).dependencies); add_to_set(dependencies, (chunk as Expression).contextual_dependencies); + + // add_to_set(dependencies, (chunk as Expression).dependencies); + (chunk as Expression).dependencies.forEach(name => { + const variable = renderer.component.var_lookup.get(name); + if (variable && !variable.hoistable) dependencies.add(name); + }); } }); - if (attribute.dependencies.size > 0) { - changes_props.push(`${attribute.name}: ${[...attribute.dependencies].join(' || ')}`); + const dynamic_dependencies = Array.from(attribute.dependencies).filter(name => { + const variable = renderer.component.var_lookup.get(name); + return is_dynamic(variable); + }); + + if (dynamic_dependencies.length > 0) { + changes_props.push(`${attribute.name}: ${dynamic_dependencies.join(' || ')}`); } }); - const arg = dependencies.size > 0 ? `{ ${Array.from(dependencies).join(', ')} }` : '{}'; + const arg = dependencies.size > 0 ? `{ ${Array.from(dependencies).join(', ')} }` : ''; renderer.blocks.push(deindent` const ${get_slot_changes} = (${arg}) => (${stringify_props(changes_props)}); @@ -149,8 +160,14 @@ export default class SlotWrapper extends Wrapper { `@transition_out(${slot}, #local);` ); - let update_conditions = [...this.dependencies].map(name => `changed.${name}`).join(' || '); - if (this.dependencies.size > 1) update_conditions = `(${update_conditions})`; + const dynamic_dependencies = Array.from(this.dependencies).filter(name => { + if (name === '$$scope') return true; + const variable = renderer.component.var_lookup.get(name); + return is_dynamic(variable); + }); + + let update_conditions = dynamic_dependencies.map(name => `changed.${name}`).join(' || '); + if (dynamic_dependencies.length > 1) update_conditions = `(${update_conditions})`; block.builders.update.add_block(deindent` if (${slot} && ${slot}.p && ${update_conditions}) { diff --git a/src/compiler/compile/render_dom/wrappers/shared/is_dynamic.ts b/src/compiler/compile/render_dom/wrappers/shared/is_dynamic.ts new file mode 100644 index 0000000000..d32ebe4594 --- /dev/null +++ b/src/compiler/compile/render_dom/wrappers/shared/is_dynamic.ts @@ -0,0 +1,10 @@ +import { Var } from '../../../../interfaces'; + +export default function is_dynamic(variable: Var) { + if (variable) { + if (variable.mutated || variable.reassigned) return true; // dynamic internal state + if (!variable.module && variable.writable && variable.export_name) return true; // writable props + } + + return false; +} \ No newline at end of file diff --git a/test/runtime/samples/component-slot-let-e/Nested.svelte b/test/runtime/samples/component-slot-let-e/Nested.svelte new file mode 100644 index 0000000000..6e7b1b1a54 --- /dev/null +++ b/test/runtime/samples/component-slot-let-e/Nested.svelte @@ -0,0 +1,7 @@ + + +
+ +
diff --git a/test/runtime/samples/component-slot-let-e/_config.js b/test/runtime/samples/component-slot-let-e/_config.js new file mode 100644 index 0000000000..1f7633da0c --- /dev/null +++ b/test/runtime/samples/component-slot-let-e/_config.js @@ -0,0 +1,20 @@ +export default { + html: ` +
+

foo

+
+ `, + + async test({ assert, target, window }) { + const div = target.querySelector('div'); + const click = new window.MouseEvent('click'); + + await div.dispatchEvent(click); + + assert.htmlEqual(target.innerHTML, ` +
+

foo

+
+ `); + } +}; diff --git a/test/runtime/samples/component-slot-let-e/main.svelte b/test/runtime/samples/component-slot-let-e/main.svelte new file mode 100644 index 0000000000..4662deef57 --- /dev/null +++ b/test/runtime/samples/component-slot-let-e/main.svelte @@ -0,0 +1,7 @@ + + + +

{someText}

+