diff --git a/src/generators/dom/visitors/Component/Component.ts b/src/generators/dom/visitors/Component/Component.ts index a0616bc587..672bb1ca26 100644 --- a/src/generators/dom/visitors/Component/Component.ts +++ b/src/generators/dom/visitors/Component/Component.ts @@ -185,12 +185,6 @@ export default function visitComponent( }); `); - if (isTopLevel) { - block.builders.mount.addLine( - `${name}._fragment.mount( ${block.target}, anchor );` - ); - } - if (local.dynamicAttributes.length) { const updates = local.dynamicAttributes.map(attribute => { if (attribute.dependencies.length) { diff --git a/src/generators/dom/visitors/Element/Binding.ts b/src/generators/dom/visitors/Element/Binding.ts index b190230527..3610ce4e75 100644 --- a/src/generators/dom/visitors/Element/Binding.ts +++ b/src/generators/dom/visitors/Element/Binding.ts @@ -91,7 +91,7 @@ export default function visitBinding( `; generator.hasComplexBindings = true; - block.builders.create.addBlock( + block.builders.hydrate.addBlock( `if ( !('${name}' in state) ) ${block.component}._bindings.push( ${handler} );` ); } else if (attribute.name === 'group') { @@ -107,7 +107,7 @@ export default function visitBinding( ? `~${snippet}.indexOf( ${state.parentNode}.__value )` : `${state.parentNode}.__value === ${snippet}`; - block.builders.create.addLine( + block.builders.hydrate.addLine( `${block.component}._bindingGroups[${bindingGroup}].push( ${state.parentNode} );` ); @@ -118,7 +118,7 @@ export default function visitBinding( updateElement = `${state.parentNode}.checked = ${condition};`; } else if (node.name === 'audio' || node.name === 'video') { generator.hasComplexBindings = true; - block.builders.create.addBlock( + block.builders.hydrate.addBlock( `${block.component}._bindings.push( ${handler} );` ); @@ -144,13 +144,15 @@ export default function visitBinding( } } - block.builders.create.addBlock(deindent` + block.builders.init.addBlock(deindent` function ${handler} () { ${lock} = true; ${setter} ${lock} = false; } + `); + block.builders.hydrate.addBlock(deindent` ${generator.helper( 'addListener' )}( ${state.parentNode}, '${eventName}', ${handler} ); diff --git a/src/generators/dom/visitors/Element/EventHandler.ts b/src/generators/dom/visitors/Element/EventHandler.ts index dca64561fd..8a84e004ca 100644 --- a/src/generators/dom/visitors/Element/EventHandler.ts +++ b/src/generators/dom/visitors/Element/EventHandler.ts @@ -68,36 +68,38 @@ export default function visitEventHandler( [✂${attribute.expression.start}-${attribute.expression.end}✂]; `; - const handler = isCustomEvent - ? deindent` - var ${handlerName} = ${generator.alias( + if (isCustomEvent) { + block.addVariable(handlerName); + + block.builders.hydrate.addBlock(deindent` + ${handlerName} = ${generator.alias( 'template' )}.events.${name}.call( ${block.component}, ${state.parentNode}, function ( event ) { ${handlerBody} }); - ` - : deindent` + `); + + block.builders.destroy.addLine(deindent` + ${handlerName}.teardown(); + `); + } else { + const handler = deindent` function ${handlerName} ( event ) { ${handlerBody} } `; - if (shouldHoist) { - generator.blocks.push( - { - render: () => handler, - } - ); - } else { - block.builders.create.addBlock(handler); - } + if (shouldHoist) { + generator.blocks.push( + { + render: () => handler, + } + ); + } else { + block.builders.init.addBlock(handler); + } - if (isCustomEvent) { - block.builders.destroy.addLine(deindent` - ${handlerName}.teardown(); - `); - } else { - block.builders.create.addLine(deindent` + block.builders.hydrate.addLine(deindent` ${generator.helper( 'addListener' )}( ${state.parentNode}, '${name}', ${handlerName} ); diff --git a/src/generators/dom/visitors/IfBlock.ts b/src/generators/dom/visitors/IfBlock.ts index 8678537ed6..2198e60c81 100644 --- a/src/generators/dom/visitors/IfBlock.ts +++ b/src/generators/dom/visitors/IfBlock.ts @@ -106,11 +106,11 @@ export default function visitIfBlock( } block.builders.create.addLine( - `${name}.create();` + `${if_name}${name}.create();` ); block.builders.claim.addLine( - `${name}.claim( ${state.parentNodes} );` + `${if_name}${name}.claim( ${state.parentNodes} );` ); if (node.needsAnchor) { @@ -145,7 +145,7 @@ function simple( const anchorNode = state.parentNode ? 'null' : 'anchor'; block.builders.mount.addLine( - `if ( ${name} ) ${name}.${mountOrIntro}( ${block.target}, anchor );` + `if ( ${name} ) ${name}.${mountOrIntro}( ${targetNode}, ${anchorNode} );` ); const parentNode = state.parentNode || `${anchor}.parentNode`; @@ -166,6 +166,7 @@ function simple( ${name}.update( changed, ${params} ); } else { ${name} = ${branch.block}( ${params}, ${block.component} ); + ${name}.create(); ${name}.mount( ${parentNode}, ${anchor} ); } ` @@ -177,6 +178,7 @@ function simple( : deindent` if ( !${name} ) { ${name} = ${branch.block}( ${params}, ${block.component} ); + ${name}.create(); ${name}.mount( ${parentNode}, ${anchor} ); } `; @@ -248,11 +250,18 @@ function compound( const parentNode = state.parentNode || `${anchor}.parentNode`; const changeBlock = deindent` - ${if_name}{ - ${name}.unmount(); - ${name}.destroy(); - } + ${hasElse ? + deindent` + ${name}.unmount(); + ${name}.destroy(); + ` : + deindent` + if ( ${name} ) { + ${name}.unmount(); + ${name}.destroy(); + }`} ${name} = ${current_block_and}${current_block}( ${params}, ${block.component} ); + ${if_name}${name}.create(); ${if_name}${name}.${mountOrIntro}( ${parentNode}, ${anchor} ); `; diff --git a/test/hydration/index.js b/test/hydration/index.js index 3f8ece97e8..26a8908b76 100644 --- a/test/hydration/index.js +++ b/test/hydration/index.js @@ -82,7 +82,7 @@ describe.only('hydration', () => { assert.htmlEqual(target.innerHTML, fs.readFileSync(`${cwd}/_after.html`, 'utf-8')); if (config.test) { - config.test(assert, target, snapshot, component); + config.test(assert, target, snapshot, component, window); } else { component.destroy(); assert.equal(target.innerHTML, ''); diff --git a/test/hydration/samples/binding-input/_after.html b/test/hydration/samples/binding-input/_after.html new file mode 100644 index 0000000000..be17352b0d --- /dev/null +++ b/test/hydration/samples/binding-input/_after.html @@ -0,0 +1,2 @@ + +

Hello world!

\ No newline at end of file diff --git a/test/hydration/samples/binding-input/_before.html b/test/hydration/samples/binding-input/_before.html new file mode 100644 index 0000000000..be17352b0d --- /dev/null +++ b/test/hydration/samples/binding-input/_before.html @@ -0,0 +1,2 @@ + +

Hello world!

\ No newline at end of file diff --git a/test/hydration/samples/binding-input/_config.js b/test/hydration/samples/binding-input/_config.js new file mode 100644 index 0000000000..86ba3fe9ec --- /dev/null +++ b/test/hydration/samples/binding-input/_config.js @@ -0,0 +1,29 @@ +export default { + data: { + name: 'world' + }, + + snapshot(target) { + return { + input: target.querySelector('input'), + p: target.querySelector('p') + }; + }, + + test(assert, target, snapshot, component, window) { + const input = target.querySelector('input'); + const p = target.querySelector('p'); + + assert.equal(input, snapshot.input); + assert.equal(p, snapshot.p); + + input.value = 'everybody'; + input.dispatchEvent(new window.Event('input')); + + assert.equal(component.get('name'), 'everybody'); + assert.htmlEqual(target.innerHTML, ` + +

Hello everybody!

+ `); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/binding-input/main.html b/test/hydration/samples/binding-input/main.html new file mode 100644 index 0000000000..d4359f73e4 --- /dev/null +++ b/test/hydration/samples/binding-input/main.html @@ -0,0 +1,2 @@ + +

Hello {{name}}!

\ No newline at end of file diff --git a/test/hydration/samples/event-handler/_after.html b/test/hydration/samples/event-handler/_after.html new file mode 100644 index 0000000000..13cd34a990 --- /dev/null +++ b/test/hydration/samples/event-handler/_after.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/hydration/samples/event-handler/_before.html b/test/hydration/samples/event-handler/_before.html new file mode 100644 index 0000000000..13cd34a990 --- /dev/null +++ b/test/hydration/samples/event-handler/_before.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/hydration/samples/event-handler/_config.js b/test/hydration/samples/event-handler/_config.js new file mode 100644 index 0000000000..4cd132f801 --- /dev/null +++ b/test/hydration/samples/event-handler/_config.js @@ -0,0 +1,26 @@ +export default { + data: { + clicked: false + }, + + snapshot(target) { + const button = target.querySelector('button'); + + return { + button + }; + }, + + test(assert, target, snapshot, component, window) { + const button = target.querySelector('button'); + assert.equal(button, snapshot.button); + + button.dispatchEvent(new window.MouseEvent('click')); + + assert.ok(component.get('clicked')); + assert.htmlEqual(target.innerHTML, ` + +

clicked!

+ `); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/event-handler/main.html b/test/hydration/samples/event-handler/main.html new file mode 100644 index 0000000000..9533175147 --- /dev/null +++ b/test/hydration/samples/event-handler/main.html @@ -0,0 +1,5 @@ + + +{{#if clicked}} +

clicked!

+{{/if}} \ No newline at end of file diff --git a/test/hydration/samples/if-block-anchor/_after.html b/test/hydration/samples/if-block-anchor/_after.html new file mode 100644 index 0000000000..31701ce3e9 --- /dev/null +++ b/test/hydration/samples/if-block-anchor/_after.html @@ -0,0 +1,4 @@ +
+

foo!

+

bar!

+
\ No newline at end of file diff --git a/test/hydration/samples/if-block-anchor/_before.html b/test/hydration/samples/if-block-anchor/_before.html new file mode 100644 index 0000000000..31701ce3e9 --- /dev/null +++ b/test/hydration/samples/if-block-anchor/_before.html @@ -0,0 +1,4 @@ +
+

foo!

+

bar!

+
\ No newline at end of file diff --git a/test/hydration/samples/if-block-anchor/_config.js b/test/hydration/samples/if-block-anchor/_config.js new file mode 100644 index 0000000000..f9acaa30ed --- /dev/null +++ b/test/hydration/samples/if-block-anchor/_config.js @@ -0,0 +1,26 @@ +export default { + data: { + foo: true, + bar: true + }, + + snapshot(target) { + const div = target.querySelector('div'); + const ps = target.querySelectorAll('p'); + + return { + div, + p0: ps[0], + p1: ps[1] + }; + }, + + test(assert, target, snapshot) { + const div = target.querySelector('div'); + const ps = target.querySelectorAll('p'); + + assert.equal(div, snapshot.div); + assert.equal(ps[0], snapshot.p0); + assert.equal(ps[1], snapshot.p1); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/if-block-anchor/main.html b/test/hydration/samples/if-block-anchor/main.html new file mode 100644 index 0000000000..b46363fecb --- /dev/null +++ b/test/hydration/samples/if-block-anchor/main.html @@ -0,0 +1,9 @@ +
+ {{#if foo}} +

foo!

+ {{/if}} + + {{#if bar}} +

bar!

+ {{/if}} +
\ No newline at end of file diff --git a/test/hydration/samples/if-block-false/_after.html b/test/hydration/samples/if-block-false/_after.html new file mode 100644 index 0000000000..17eb5acc05 --- /dev/null +++ b/test/hydration/samples/if-block-false/_after.html @@ -0,0 +1,2 @@ +

before

+

after

\ No newline at end of file diff --git a/test/hydration/samples/if-block-false/_before.html b/test/hydration/samples/if-block-false/_before.html new file mode 100644 index 0000000000..17eb5acc05 --- /dev/null +++ b/test/hydration/samples/if-block-false/_before.html @@ -0,0 +1,2 @@ +

before

+

after

\ No newline at end of file diff --git a/test/hydration/samples/if-block-false/_config.js b/test/hydration/samples/if-block-false/_config.js new file mode 100644 index 0000000000..ba071e9910 --- /dev/null +++ b/test/hydration/samples/if-block-false/_config.js @@ -0,0 +1,19 @@ +export default { + data: { + foo: false + }, + + snapshot(target) { + const p = target.querySelector('p'); + + return { + p + }; + }, + + test(assert, target, snapshot) { + const p = target.querySelector('p'); + + assert.equal(p, snapshot.p); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/if-block-false/main.html b/test/hydration/samples/if-block-false/main.html new file mode 100644 index 0000000000..4d42d3e7d7 --- /dev/null +++ b/test/hydration/samples/if-block-false/main.html @@ -0,0 +1,5 @@ +

before

+{{#if foo}} +

foo!

+{{/if}} +

after

\ No newline at end of file diff --git a/test/hydration/samples/if-block-update/_after.html b/test/hydration/samples/if-block-update/_after.html new file mode 100644 index 0000000000..5ed8b34a53 --- /dev/null +++ b/test/hydration/samples/if-block-update/_after.html @@ -0,0 +1 @@ +

foo!

\ No newline at end of file diff --git a/test/hydration/samples/if-block-update/_before.html b/test/hydration/samples/if-block-update/_before.html new file mode 100644 index 0000000000..5ed8b34a53 --- /dev/null +++ b/test/hydration/samples/if-block-update/_before.html @@ -0,0 +1 @@ +

foo!

\ No newline at end of file diff --git a/test/hydration/samples/if-block-update/_config.js b/test/hydration/samples/if-block-update/_config.js new file mode 100644 index 0000000000..185dacb1e7 --- /dev/null +++ b/test/hydration/samples/if-block-update/_config.js @@ -0,0 +1,23 @@ +export default { + data: { + foo: true, + bar: false + }, + + snapshot(target) { + const p = target.querySelector('p'); + + return { + p + }; + }, + + test(assert, target, snapshot, component) { + const p = target.querySelector('p'); + + assert.equal(p, snapshot.p); + + component.set({ foo: false, bar: true }); + assert.htmlEqual(target.innerHTML, `

bar!

`); + } +}; \ No newline at end of file diff --git a/test/hydration/samples/if-block-update/main.html b/test/hydration/samples/if-block-update/main.html new file mode 100644 index 0000000000..82c5a193fe --- /dev/null +++ b/test/hydration/samples/if-block-update/main.html @@ -0,0 +1,7 @@ +{{#if foo}} +

foo!

+{{/if}} + +{{#if bar}} +

bar!

+{{/if}} \ No newline at end of file