diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 386611df79..db3c383fec 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -252,7 +252,11 @@ export default class Block { const noop = x`@noop`; properties.key = key - properties.first = this.first; + + if (this.first) { + properties.first = x`null`; + this.chunks.hydrate.push(b`this.first = ${this.first};`); + } if (this.chunks.create.length === 0 && this.chunks.hydrate.length === 0) { properties.create = noop; diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts index 793b9935ab..f262b00ccf 100644 --- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts @@ -3,12 +3,13 @@ import Renderer from '../Renderer'; import Block from '../Block'; import AwaitBlock from '../../nodes/AwaitBlock'; import create_debugging_comment from './shared/create_debugging_comment'; -import { b } from 'code-red'; +import { b, x } from 'code-red'; import FragmentWrapper from './Fragment'; import PendingBlock from '../../nodes/PendingBlock'; import ThenBlock from '../../nodes/ThenBlock'; import CatchBlock from '../../nodes/CatchBlock'; import { Identifier } from '../../../interfaces'; +import { changed } from './shared/changed'; class AwaitBlockBranch extends Wrapper { node: PendingBlock | ThenBlock | CatchBlock; @@ -136,22 +137,23 @@ export default class AwaitBlockWrapper extends Wrapper { block.maintain_context = true; - const info_props = [ - '#ctx', - 'current: null', - 'token: null', - this.pending.block.name && `pending: ${this.pending.block.name}`, - this.then.block.name && `then: ${this.then.block.name}`, - this.catch.block.name && `catch: ${this.catch.block.name}`, - this.then.block.name && `value: '${this.node.value}'`, - this.catch.block.name && `error: '${this.node.error}'`, - this.pending.block.has_outro_method && `blocks: [,,,]` - ].filter(Boolean); + const info_props: any = x`{ + ctx: #ctx, + current: null, + token: null, + pending: ${this.pending.block.name}, + then: ${this.then.block.name}, + catch: ${this.catch.block.name}, + value: ${this.then.block.name && this.node.value}, + error: ${this.catch.block.name && this.node.error}, + blocks: ${this.pending.block.has_outro_method && x`[,,,]`} + }`; + + // TODO move this into code-red + info_props.properties = info_props.properties.filter(prop => prop.value); block.chunks.init.push(b` - let ${info} = { - ${info_props.join(',\n')} - }; + let ${info} = ${info_props}; `); block.chunks.init.push(b` @@ -183,18 +185,13 @@ export default class AwaitBlockWrapper extends Wrapper { block.chunks.intro.push(b`@transition_in(${info}.block);`); } - const conditions = []; const dependencies = this.node.expression.dynamic_dependencies(); if (dependencies.length > 0) { - conditions.push( - `(${dependencies.map(dep => `'${dep}' in changed`).join(' || ')})` - ); - - conditions.push( - `${promise} !== (${promise} = ${snippet})`, - `@handle_promise(${promise}, ${info})` - ); + let condition = x` + ${changed(dependencies)} && + ${promise} !== (${promise} = ${snippet}) && + @handle_promise(${promise}, ${info})`; block.chunks.update.push( b`${info}.ctx = #ctx;` @@ -202,21 +199,21 @@ export default class AwaitBlockWrapper extends Wrapper { if (this.pending.block.has_update_method) { block.chunks.update.push(b` - if (${conditions.join(' && ')}) { + if (${condition}) { // nothing } else { - ${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved)); + ${info}.block.p(#changed, @assign(@assign({}, #ctx), ${info}.resolved)); } `); } else { block.chunks.update.push(b` - ${conditions.join(' && ')} + ${condition} `); } } else { if (this.pending.block.has_update_method) { block.chunks.update.push(b` - ${info}.block.p(changed, @assign(@assign({}, #ctx), ${info}.resolved)); + ${info}.block.p(#changed, @assign(@assign({}, #ctx), ${info}.resolved)); `); } } @@ -231,7 +228,7 @@ export default class AwaitBlockWrapper extends Wrapper { } block.chunks.destroy.push(b` - ${info}.block.d(${parent_node ? '' : 'detaching'}); + ${info}.block.d(${parent_node ? null : 'detaching'}); ${info}.token = null; ${info} = null; `); diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index 86899c8ea3..f12f4a603c 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -56,9 +56,9 @@ class IfBlockBranch extends Wrapper { if (should_cache) { this.condition = block.get_unique_name(`show_if`); - this.snippet = expression.node; + this.snippet = (expression.manipulate(block) as Node); } else { - this.condition = expression.node; + this.condition = expression.manipulate(block); } } @@ -181,14 +181,14 @@ export default class IfBlockWrapper extends Wrapper { : (this.next && this.next.var) || 'null'; const has_else = !(this.branches[this.branches.length - 1].condition); - const if_name = has_else ? '' : `if (${name}) `; + const if_exists_condition = has_else ? x`true` : name; const dynamic = this.branches[0].block.has_update_method; // can use [0] as proxy for all, since they necessarily have the same value const has_intros = this.branches[0].block.has_intro_method; const has_outros = this.branches[0].block.has_outro_method; const has_transitions = has_intros || has_outros; - const vars = { name, anchor, if_name, has_else, has_transitions }; + const vars = { name, anchor, if_exists_condition, has_else, has_transitions }; const detaching = (parent_node && parent_node !== '@_document.head') ? '' : 'detaching'; @@ -212,11 +212,11 @@ export default class IfBlockWrapper extends Wrapper { } } - block.chunks.create.push(b`${if_name}${name}.c();`); + block.chunks.create.push(b`if (${if_exists_condition}) ${name}.c();`); if (parent_nodes && this.renderer.options.hydratable) { block.chunks.claim.push( - b`${if_name}${name}.l(${parent_nodes});` + b`if (${if_exists_condition}) ${name}.l(${parent_nodes});` ); } @@ -243,7 +243,7 @@ export default class IfBlockWrapper extends Wrapper { parent_node: string, _parent_nodes: string, dynamic, - { name, anchor, has_else, if_name, has_transitions }, + { name, anchor, has_else, if_exists_condition, has_transitions }, detaching ) { const select_block_type = this.renderer.component.get_unique_name(`select_block_type`); @@ -253,7 +253,7 @@ export default class IfBlockWrapper extends Wrapper { /* eslint-disable @typescript-eslint/indent,indent */ if (this.needs_update) { block.chunks.init.push(b` - function ${select_block_type}(changed, ctx) { + function ${select_block_type}(#changed, #ctx) { ${this.branches.map(({ dependencies, condition, snippet, block }) => condition ? b` ${snippet && ( @@ -267,7 +267,7 @@ export default class IfBlockWrapper extends Wrapper { `); } else { block.chunks.init.push(b` - function ${select_block_type}(changed, ctx) { + function ${select_block_type}(#changed, #ctx) { ${this.branches.map(({ condition, snippet, block }) => condition ? `if (${snippet || condition}) return ${block.name};` : `return ${block.name};`)} @@ -277,22 +277,22 @@ export default class IfBlockWrapper extends Wrapper { /* eslint-enable @typescript-eslint/indent,indent */ block.chunks.init.push(b` - var ${current_block_type} = ${select_block_type}(null, ctx); - var ${name} = ${current_block_type_and}${current_block_type}(ctx); + let ${current_block_type} = ${select_block_type}(null, #ctx); + let ${name} = ${current_block_type_and}${current_block_type}(#ctx); `); const initial_mount_node = parent_node || '#target'; const anchor_node = parent_node ? 'null' : 'anchor'; block.chunks.mount.push( - b`${if_name}${name}.m(${initial_mount_node}, ${anchor_node});` + b`if (${if_exists_condition}) ${name}.m(${initial_mount_node}, ${anchor_node});` ); if (this.needs_update) { const update_mount_node = this.get_update_mount_node(anchor); const change_block = b` - ${if_name}${name}.d(1); - ${name} = ${current_block_type_and}${current_block_type}(ctx); + ${if_exists_condition}${name}.d(1); + ${name} = ${current_block_type_and}${current_block_type}(#ctx); if (${name}) { ${name}.c(); ${has_transitions && `@transition_in(${name}, 1);`} @@ -302,24 +302,24 @@ export default class IfBlockWrapper extends Wrapper { if (dynamic) { block.chunks.update.push(b` - if (${current_block_type} === (${current_block_type} = ${select_block_type}(changed, ctx)) && ${name}) { - ${name}.p(changed, ctx); + if (${current_block_type} === (${current_block_type} = ${select_block_type}(#changed, #ctx)) && ${name}) { + ${name}.p(#changed, #ctx); } else { ${change_block} } `); } else { block.chunks.update.push(b` - if (${current_block_type} !== (${current_block_type} = ${select_block_type}(changed, ctx))) { + if (${current_block_type} !== (${current_block_type} = ${select_block_type}(#changed, #ctx))) { ${change_block} } `); } } else if (dynamic) { - block.chunks.update.push(b`${name}.p(changed, ctx);`); + block.chunks.update.push(b`${name}.p(#changed, #ctx);`); } - block.chunks.destroy.push(b`${if_name}${name}.d(${detaching});`); + block.chunks.destroy.push(b`if (${if_exists_condition}) ${name}.d(${detaching});`); } // if any of the siblings have outros, we need to keep references to the blocks @@ -347,15 +347,15 @@ export default class IfBlockWrapper extends Wrapper { /* eslint-disable @typescript-eslint/indent,indent */ block.chunks.init.push(b` - var ${if_block_creators} = [ + const ${if_block_creators} = [ ${this.branches.map(branch => branch.block.name).join(',\n')} ]; - var ${if_blocks} = []; + const ${if_blocks} = []; ${this.needs_update ? b` - function ${select_block_type}(changed, ctx) { + function ${select_block_type}(#changed, #ctx) { ${this.branches.map(({ dependencies, condition, snippet }, i) => condition ? b` ${snippet && `if ((${condition} == null) || ${dependencies.map(n => `changed.${n}`).join(' || ')}) ${condition} = !!(${snippet})`} @@ -365,7 +365,7 @@ export default class IfBlockWrapper extends Wrapper { } ` : b` - function ${select_block_type}(changed, ctx) { + function ${select_block_type}(#changed, #ctx) { ${this.branches.map(({ condition, snippet }, i) => condition ? `if (${snippet || condition}) return ${String(i)};` : `return ${i};`)} @@ -377,13 +377,13 @@ export default class IfBlockWrapper extends Wrapper { if (has_else) { block.chunks.init.push(b` - ${current_block_type_index} = ${select_block_type}(null, ctx); - ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx); + ${current_block_type_index} = ${select_block_type}(null, #ctx); + ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](#ctx); `); } else { block.chunks.init.push(b` - if (~(${current_block_type_index} = ${select_block_type}(null, ctx))) { - ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx); + if (~(${current_block_type_index} = ${select_block_type}(null, #ctx))) { + ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](#ctx); } `); } @@ -409,7 +409,7 @@ export default class IfBlockWrapper extends Wrapper { const create_new_block = b` ${name} = ${if_blocks}[${current_block_type_index}]; if (!${name}) { - ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](ctx); + ${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](#ctx); ${name}.c(); } ${has_transitions && `@transition_in(${name}, 1);`} @@ -436,25 +436,25 @@ export default class IfBlockWrapper extends Wrapper { if (dynamic) { block.chunks.update.push(b` - var ${previous_block_index} = ${current_block_type_index}; - ${current_block_type_index} = ${select_block_type}(changed, ctx); + let ${previous_block_index} = ${current_block_type_index}; + ${current_block_type_index} = ${select_block_type}(#changed, #ctx); if (${current_block_type_index} === ${previous_block_index}) { - ${if_current_block_type_index}${if_blocks}[${current_block_type_index}].p(changed, ctx); + ${if_current_block_type_index}${if_blocks}[${current_block_type_index}].p(#changed, #ctx); } else { ${change_block} } `); } else { block.chunks.update.push(b` - var ${previous_block_index} = ${current_block_type_index}; - ${current_block_type_index} = ${select_block_type}(changed, ctx); + let ${previous_block_index} = ${current_block_type_index}; + ${current_block_type_index} = ${select_block_type}(#changed, #ctx); if (${current_block_type_index} !== ${previous_block_index}) { ${change_block} } `); } } else if (dynamic) { - block.chunks.update.push(b`${name}.p(changed, ctx);`); + block.chunks.update.push(b`${name}.p(#changed, #ctx);`); } block.chunks.destroy.push(b` @@ -467,7 +467,7 @@ export default class IfBlockWrapper extends Wrapper { parent_node: string, _parent_nodes: string, dynamic, - { name, anchor, if_name, has_transitions }, + { name, anchor, if_exists_condition, has_transitions }, detaching ) { const branch = this.branches[0]; @@ -475,7 +475,7 @@ export default class IfBlockWrapper extends Wrapper { if (branch.snippet) block.add_variable(branch.condition, branch.snippet); block.chunks.init.push(b` - var ${name} = (${branch.condition}) && ${branch.block.name}(ctx); + let ${name} = ${branch.condition} && ${branch.block.name}(#ctx); `); const initial_mount_node = parent_node || '#target'; @@ -491,10 +491,10 @@ export default class IfBlockWrapper extends Wrapper { const enter = dynamic ? b` if (${name}) { - ${name}.p(changed, ctx); + ${name}.p(#changed, #ctx); ${has_transitions && `@transition_in(${name}, 1);`} } else { - ${name} = ${branch.block.name}(ctx); + ${name} = ${branch.block.name}(#ctx); ${name}.c(); ${has_transitions && `@transition_in(${name}, 1);`} ${name}.m(${update_mount_node}, ${anchor}); @@ -502,7 +502,7 @@ export default class IfBlockWrapper extends Wrapper { ` : b` if (!${name}) { - ${name} = ${branch.block.name}(ctx); + ${name} = ${branch.block.name}(#ctx); ${name}.c(); ${has_transitions && `@transition_in(${name}, 1);`} ${name}.m(${update_mount_node}, ${anchor}); @@ -539,10 +539,10 @@ export default class IfBlockWrapper extends Wrapper { } } else if (dynamic) { block.chunks.update.push( - b`if (${branch.condition}) ${name}.p(changed, ctx);` + b`if (${branch.condition}) ${name}.p(#changed, #ctx);` ); } - block.chunks.destroy.push(b`${if_name}${name}.d(${detaching});`); + block.chunks.destroy.push(b`if (${if_exists_condition}) ${name}.d(${detaching});`); } } diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index e5e8c01bb0..6d02d4210c 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -15,6 +15,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope'; import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; import { Identifier } from '../../../../interfaces'; +import { changed } from '../shared/changed'; export default class InlineComponentWrapper extends Wrapper { var: Identifier; @@ -119,7 +120,7 @@ export default class InlineComponentWrapper extends Wrapper { const updates: string[] = []; let props; - const name_changes = block.get_unique_name(`${name}_changes`); + const name_changes = block.get_unique_name(`${name.name}_changes`); const uses_spread = !!this.node.attributes.find(a => a.is_spread); @@ -214,7 +215,7 @@ export default class InlineComponentWrapper extends Wrapper { const dynamic_attributes = this.node.attributes.filter(a => a.get_dependencies().length > 0); if (!uses_spread && (dynamic_attributes.length > 0 || this.node.bindings.length > 0 || non_let_dependencies.length > 0)) { - updates.push(`const ${name_changes} = {};`); + updates.push(b`const ${name_changes} = {};`); } if (this.node.attributes.length) { @@ -224,7 +225,7 @@ export default class InlineComponentWrapper extends Wrapper { const initial_props = []; const changes = []; - const all_dependencies = new Set(); + const all_dependencies: Set = new Set(); this.node.attributes.forEach(attr => { add_to_set(all_dependencies, attr.dependencies); @@ -266,18 +267,24 @@ export default class InlineComponentWrapper extends Wrapper { } `); - const conditions = Array.from(all_dependencies).map(dep => `changed.${dep}`).join(' || '); + if (all_dependencies.size) { + const condition = changed(Array.from(all_dependencies)); - updates.push(b` - const ${name_changes} = ${conditions ? `(${conditions}) ? @get_spread_update(${levels}, [ - ${changes.join(',\n')} - ]) : {}` : '{}'}; - `); + updates.push(b` + const ${name_changes} = ${condition} ? @get_spread_update(${levels}, [ + ${changes.join(',\n')} + ]) : {} + `); + } else { + updates.push(b` + const ${name_changes} = {}; + `); + } } else { dynamic_attributes.forEach((attribute: Attribute) => { const dependencies = attribute.get_dependencies(); if (dependencies.length > 0) { - const condition = dependencies.map(dependency => `changed.${dependency}`).join(' || '); + const condition = changed(dependencies); updates.push(b` if (${condition}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)}; @@ -288,7 +295,7 @@ export default class InlineComponentWrapper extends Wrapper { } if (non_let_dependencies.length > 0) { - updates.push(`if (${non_let_dependencies.map(n => `changed.${n}`).join(' || ')}) ${name_changes}.$$scope = { changed: #changed, ctx: #ctx };`); + updates.push(`if (${changed(non_let_dependencies)} ${name_changes}.$$scope = { changed: #changed, ctx: #ctx };`); } const munged_bindings = this.node.bindings.map(binding => {