From d274d08734b2cdbe1eda51cf06d60d7df710a569 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Wed, 19 Apr 2017 13:52:36 -0400 Subject: [PATCH] only create anchors for if blocks when necessary --- src/generators/dom/preprocess.js | 48 ++++++++++++------- src/generators/dom/visitors/IfBlock.js | 24 ++++++---- src/generators/dom/visitors/Text.js | 2 +- .../js/samples/if-block-no-update/expected.js | 2 +- test/js/samples/if-block-simple/expected.js | 2 +- .../use-elements-as-anchors/expected.js | 27 +++++------ .../samples/if-block-widget/_config.js | 21 ++++++-- 7 files changed, 81 insertions(+), 45 deletions(-) diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index 320724c332..6009f4dec8 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -223,7 +223,7 @@ const preprocessors = { } }; -function preprocessChildren ( generator, block, state, node ) { +function preprocessChildren ( generator, block, state, node, isTopLevel ) { // glue text nodes together const cleaned = []; let lastChild; @@ -238,16 +238,43 @@ function preprocessChildren ( generator, block, state, node ) { cleaned.push( child ); } - if ( lastChild ) lastChild.next = child; lastChild = child; }); - node.children = cleaned; + if ( isTopLevel ) { + // trim leading and trailing whitespace from the top level + const firstChild = cleaned[0]; + if ( firstChild && firstChild.type === 'Text' ) { + firstChild.data = trimStart( firstChild.data ); + if ( !firstChild.data ) cleaned.shift(); + } + + const lastChild = cleaned[ cleaned.length - 1 ]; + if ( lastChild && lastChild.type === 'Text' ) { + lastChild.data = trimEnd( lastChild.data ); + if ( !lastChild.data ) cleaned.pop(); + } + } + + lastChild = null; cleaned.forEach( child => { const preprocess = preprocessors[ child.type ]; if ( preprocess ) preprocess( generator, block, state, child ); + + if ( lastChild ) { + lastChild.next = child; + lastChild.needsAnchor = !child._state.name; + } + + lastChild = child; }); + + if ( lastChild ) { + lastChild.needsAnchor = !state.parentNode; + } + + node.children = cleaned; } export default function preprocess ( generator, state, node ) { @@ -268,21 +295,8 @@ export default function preprocess ( generator, state, node ) { }); generator.blocks.push( block ); - preprocessChildren( generator, block, state, node ); + preprocessChildren( generator, block, state, node, true ); block.hasUpdateMethod = block.dependencies.size > 0; - // trim leading and trailing whitespace from the top level - const firstChild = node.children[0]; - if ( firstChild && firstChild.type === 'Text' ) { - firstChild.data = trimStart( firstChild.data ); - if ( !firstChild.data ) node.children.shift(); - } - - const lastChild = node.children[ node.children.length - 1 ]; - if ( lastChild && lastChild.type === 'Text' ) { - lastChild.data = trimEnd( lastChild.data ); - if ( !lastChild.data ) node.children.pop(); - } - return block; } \ No newline at end of file diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index 593a7ca986..d9fd1b81c7 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -41,12 +41,16 @@ function visitChildren ( generator, block, state, node ) { export default function visitIfBlock ( generator, block, state, node ) { const name = generator.getUniqueName( `if_block` ); - const anchor = generator.getUniqueName( `${name}_anchor` ); + const anchor = node.needsAnchor ? block.getUniqueName( `${name}_anchor` ) : ( node.next && node.next._state.name ) || 'null'; const params = block.params.join( ', ' ); const vars = { name, anchor, params }; - block.createAnchor( anchor, state.parentNode ); + if ( node.needsAnchor ) { + block.createAnchor( anchor, state.parentNode ); + } else if ( node.next ) { + node.next.usedAsAnchor = true; + } const branches = getBranches( generator, block, state, node, generator.getUniqueName( `create_if_block` ) ); const dynamic = branches.some( branch => branch.dynamic ); @@ -70,11 +74,13 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor const isToplevel = !state.parentNode; if ( isToplevel ) { - block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, ${anchor} );` ); + block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, null );` ); } else { block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` ); } + const parentNode = state.parentNode || `${anchor}.parentNode`; + if ( dynamic ) { block.builders.update.addBlock( deindent` if ( ${branch.condition} ) { @@ -82,7 +88,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor ${name}.update( changed, ${params} ); } else { ${name} = ${branch.block}( ${params}, ${block.component} ); - ${name}.mount( ${anchor}.parentNode, ${anchor} ); + ${name}.mount( ${parentNode}, ${anchor} ); } } else if ( ${name} ) { ${name}.destroy( true ); @@ -94,7 +100,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor if ( ${branch.condition} ) { if ( !${name} ) { ${name} = ${branch.block}( ${params}, ${block.component} ); - ${name}.mount( ${anchor}.parentNode, ${anchor} ); + ${name}.mount( ${parentNode}, ${anchor} ); } } else if ( ${name} ) { ${name}.destroy( true ); @@ -122,11 +128,13 @@ function compound ( generator, block, state, node, branches, dynamic, { name, an const isToplevel = !state.parentNode; if ( isToplevel ) { - block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, ${anchor} );` ); + block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, null );` ); } else { block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` ); } + const parentNode = state.parentNode || `${anchor}.parentNode`; + if ( dynamic ) { block.builders.update.addBlock( deindent` if ( ${current_block} === ( ${current_block} = ${getBlock}( ${params} ) ) && ${name} ) { @@ -134,7 +142,7 @@ function compound ( generator, block, state, node, branches, dynamic, { name, an } else { if ( ${name} ) ${name}.destroy( true ); ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); - if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); + if ( ${name} ) ${name}.mount( ${parentNode}, ${anchor} ); } ` ); } else { @@ -142,7 +150,7 @@ function compound ( generator, block, state, node, branches, dynamic, { name, an if ( ${current_block} !== ( ${current_block} = ${getBlock}( ${params} ) ) ) { if ( ${name} ) ${name}.destroy( true ); ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); - if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); + if ( ${name} ) ${name}.mount( ${parentNode}, ${anchor} ); } ` ); } diff --git a/src/generators/dom/visitors/Text.js b/src/generators/dom/visitors/Text.js index 052c4e58a7..9abb0fa19e 100644 --- a/src/generators/dom/visitors/Text.js +++ b/src/generators/dom/visitors/Text.js @@ -2,5 +2,5 @@ export default function visitText ( generator, block, state, node ) { if ( !node._state.shouldCreate ) return; - block.addElement( node._state.name, `${generator.helper( 'createText' )}( ${JSON.stringify( node.data )} )`, state.parentNode, false ); + block.addElement( node._state.name, `${generator.helper( 'createText' )}( ${JSON.stringify( node.data )} )`, state.parentNode, node.usedAsAnchor ); } \ No newline at end of file diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index 1ed5eb2e7f..ef158af47d 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -14,7 +14,7 @@ function create_main_fragment ( state, component ) { return { mount: function ( target, anchor ) { insertNode( if_block_anchor, target, anchor ); - if ( if_block ) if_block.mount( target, if_block_anchor ); + if ( if_block ) if_block.mount( target, null ); }, update: function ( changed, state ) { diff --git a/test/js/samples/if-block-simple/expected.js b/test/js/samples/if-block-simple/expected.js index fcdd72f55d..c31e4ae914 100644 --- a/test/js/samples/if-block-simple/expected.js +++ b/test/js/samples/if-block-simple/expected.js @@ -8,7 +8,7 @@ function create_main_fragment ( state, component ) { return { mount: function ( target, anchor ) { insertNode( if_block_anchor, target, anchor ); - if ( if_block ) if_block.mount( target, if_block_anchor ); + if ( if_block ) if_block.mount( target, null ); }, update: function ( changed, state ) { diff --git a/test/js/samples/use-elements-as-anchors/expected.js b/test/js/samples/use-elements-as-anchors/expected.js index e72585e606..792dac264e 100644 --- a/test/js/samples/use-elements-as-anchors/expected.js +++ b/test/js/samples/use-elements-as-anchors/expected.js @@ -2,13 +2,12 @@ import { appendNode, assign, createComment, createElement, createText, detachNod function create_main_fragment ( state, component ) { var div = createElement( 'div' ); - var if_block_anchor = createComment(); - appendNode( if_block_anchor, div ); var if_block = state.a && create_if_block( state, component ); if ( if_block ) if_block.mount( div, null ); - appendNode( createText( "\n\n\t" ), div ); + var text = createText( "\n\n\t" ); + appendNode( text, div ); var p = createElement( 'p' ); appendNode( p, div ); appendNode( createText( "this can be used as an anchor" ), p ); @@ -17,15 +16,14 @@ function create_main_fragment ( state, component ) { var if_block_1 = state.b && create_if_block_1( state, component ); if ( if_block_1 ) if_block_1.mount( div, null ); - var if_block_1_anchor = createComment(); - appendNode( if_block_1_anchor, div ); - - appendNode( createText( "\n\n\t" ), div ); + var text_3 = createText( "\n\n\t" ); + appendNode( text_3, div ); var if_block_2 = state.c && create_if_block_2( state, component ); if ( if_block_2 ) if_block_2.mount( div, null ); - appendNode( createText( "\n\n\t" ), div ); + var text_4 = createText( "\n\n\t" ); + appendNode( text_4, div ); var p_1 = createElement( 'p' ); appendNode( p_1, div ); appendNode( createText( "so can this" ), p_1 ); @@ -34,7 +32,8 @@ function create_main_fragment ( state, component ) { var if_block_3 = state.d && create_if_block_3( state, component ); if ( if_block_3 ) if_block_3.mount( div, null ); - appendNode( createText( "\n\n\t" ), div ); + var text_7 = createText( "\n\n\t" ); + appendNode( text_7, div ); var text_8 = createText( "\n\n" ); var if_block_4_anchor = createComment(); @@ -45,14 +44,14 @@ function create_main_fragment ( state, component ) { insertNode( div, target, anchor ); insertNode( text_8, target, anchor ); insertNode( if_block_4_anchor, target, anchor ); - if ( if_block_4 ) if_block_4.mount( target, if_block_4_anchor ); + if ( if_block_4 ) if_block_4.mount( target, null ); }, update: function ( changed, state ) { if ( state.a ) { if ( !if_block ) { if_block = create_if_block( state, component ); - if_block.mount( if_block_anchor.parentNode, p ); + if_block.mount( div, text ); } } else if ( if_block ) { if_block.destroy( true ); @@ -62,7 +61,7 @@ function create_main_fragment ( state, component ) { if ( state.b ) { if ( !if_block_1 ) { if_block_1 = create_if_block_1( state, component ); - if_block_1.mount( if_block_1_anchor.parentNode, if_block_1_anchor ); + if_block_1.mount( div, text_3 ); } } else if ( if_block_1 ) { if_block_1.destroy( true ); @@ -72,7 +71,7 @@ function create_main_fragment ( state, component ) { if ( state.c ) { if ( !if_block_2 ) { if_block_2 = create_if_block_2( state, component ); - if_block_2.mount( if_block_2_anchor.parentNode, p_2 ); + if_block_2.mount( div, text_4 ); } } else if ( if_block_2 ) { if_block_2.destroy( true ); @@ -82,7 +81,7 @@ function create_main_fragment ( state, component ) { if ( state.d ) { if ( !if_block_3 ) { if_block_3 = create_if_block_3( state, component ); - if_block_3.mount( if_block_3_anchor.parentNode, null ); + if_block_3.mount( div, text_7 ); } } else if ( if_block_3 ) { if_block_3.destroy( true ); diff --git a/test/runtime/samples/if-block-widget/_config.js b/test/runtime/samples/if-block-widget/_config.js index 40d9d050e9..b82b4dfeb9 100644 --- a/test/runtime/samples/if-block-widget/_config.js +++ b/test/runtime/samples/if-block-widget/_config.js @@ -2,11 +2,26 @@ export default { data: { visible: true }, - html: 'before\n

Widget

\nafter', + + html: ` + before +

Widget

+ after + `, + test ( assert, component, target ) { component.set({ visible: false }); - assert.equal( target.innerHTML, 'before\n\nafter' ); + assert.htmlEqual( target.innerHTML, ` + before + + after + ` ); + component.set({ visible: true }); - assert.equal( target.innerHTML, 'before\n

Widget

\nafter' ); + assert.htmlEqual( target.innerHTML, ` + before +

Widget

+ after + ` ); } };