From 92b49eed4e2047d51d6f18c4a2b426b1516a7ae3 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 11:49:59 -0400 Subject: [PATCH 1/8] more tidying up --- src/generators/dom/index.js | 13 ++++--------- src/generators/dom/preprocess.js | 6 ++++++ src/generators/dom/visitors/Component/Component.js | 2 -- src/generators/dom/visitors/EachBlock.js | 12 +++++------- .../dom/visitors/Element/EventHandler.js | 2 +- src/generators/dom/visitors/IfBlock.js | 14 +++++--------- .../samples/component-yield-parent/_config.js | 12 +++++++++--- 7 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index c8d108b71efd..4c6e64ec23ed 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -24,10 +24,6 @@ class DomGenerator extends Generator { }; } - addBlock ( block ) { - this.blocks.push( block ); - } - helper ( name ) { if ( this.options.dev && `${name}Dev` in shared ) { name = `${name}Dev`; @@ -59,8 +55,6 @@ export default function dom ( parsed, source, options ) { visit( generator, block, state, node ); }); - generator.addBlock( block ); - const builders = { main: new CodeBuilder(), init: new CodeBuilder(), @@ -68,7 +62,7 @@ export default function dom ( parsed, source, options ) { }; if ( options.dev ) { - builders._set.addBlock ( deindent` + builders._set.addBlock( deindent` if ( typeof newState !== 'object' ) { throw new Error( 'Component .set was called without an object of data key-values to update.' ); } @@ -137,8 +131,9 @@ export default function dom ( parsed, source, options ) { ` ); } - let i = generator.blocks.length; - while ( i-- ) builders.main.addBlock( generator.blocks[i].render() ); + generator.blocks.forEach( block => { + builders.main.addBlock( block.render() ); + }); builders.init.addLine( `this._torndown = false;` ); diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index 5350642cbf92..6a8ba20fe927 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -19,6 +19,7 @@ const preprocessors = { name: generator.getUniqueName( `create_if_block` ) }); + generator.blocks.push( node._block ); preprocessChildren( generator, node._block, node.children ); block.addDependencies( node._block.dependencies ); @@ -29,6 +30,7 @@ const preprocessors = { name: generator.getUniqueName( `create_if_block` ) }); + generator.blocks.push( node.else._block ); preprocessChildren( generator, node.else._block, node.else.children ); block.addDependencies( node.else._block.dependencies ); } @@ -77,6 +79,7 @@ const preprocessors = { params: block.params.concat( listName, context, indexName ) }); + generator.blocks.push( node._block ); preprocessChildren( generator, node._block, node.children ); block.addDependencies( node._block.dependencies ); @@ -85,6 +88,7 @@ const preprocessors = { name: generator.getUniqueName( `${node._block.name}_else` ) }); + generator.blocks.push( node.else._block ); preprocessChildren( generator, node.else._block, node.else.children ); } }, @@ -115,6 +119,7 @@ const preprocessors = { name: generator.getUniqueName( `create_${name}_yield_fragment` ) }); + generator.blocks.push( node._block ); preprocessChildren( generator, node._block, node.children ); } @@ -149,6 +154,7 @@ export default function preprocess ( generator, children ) { dependencies: new Set() }); + generator.blocks.push( block ); preprocessChildren( generator, block, children ); return block; diff --git a/src/generators/dom/visitors/Component/Component.js b/src/generators/dom/visitors/Component/Component.js index fc2729d202be..60905a77294e 100644 --- a/src/generators/dom/visitors/Component/Component.js +++ b/src/generators/dom/visitors/Component/Component.js @@ -118,8 +118,6 @@ export default function visitComponent ( generator, block, state, node ) { ); componentInitProperties.push( `_yield: ${yieldFragment}`); - - generator.addBlock( childBlock ); } const statements = []; diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index e352d2cf8538..155797eb1edc 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -75,25 +75,23 @@ export default function visitEachBlock ( generator, block, state, node ) { ` ); } - const childBlock = node._block; - const childState = Object.assign( {}, state, { parentNode: null, inEachBlock: true }); node.children.forEach( child => { - visit( generator, childBlock, childState, child ); + visit( generator, node._block, childState, child ); }); - generator.addBlock( childBlock ); - if ( node.else ) { + const childState = Object.assign( {}, state, { + parentNode: null + }); + node.else.children.forEach( child => { visit( generator, node.else._block, childState, child ); }); - - generator.addBlock( node.else._block ); } } diff --git a/src/generators/dom/visitors/Element/EventHandler.js b/src/generators/dom/visitors/Element/EventHandler.js index 3800b528a5db..f2affc2708a3 100644 --- a/src/generators/dom/visitors/Element/EventHandler.js +++ b/src/generators/dom/visitors/Element/EventHandler.js @@ -75,7 +75,7 @@ export default function visitEventHandler ( generator, block, state, node, attri `; if ( shouldHoist ) { - generator.addBlock({ + generator.blocks.push({ render: () => handler }); } else { diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index 5ff5f0565dcf..dab0d5b821ac 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -11,7 +11,7 @@ function getConditionsAndBlocks ( generator, block, state, node ) { block: node._block.name }]; - generateBlock( generator, block, state, node ); + visitChildren( generator, block, state, node ); if ( isElseIf( node.else ) ) { conditionsAndBlocks.push( @@ -24,25 +24,21 @@ function getConditionsAndBlocks ( generator, block, state, node ) { }); if ( node.else ) { - generateBlock( generator, block, state, node.else ); + visitChildren( generator, block, state, node.else ); } } return conditionsAndBlocks; } -function generateBlock ( generator, block, state, node ) { - const childBlock = node._block; - +function visitChildren ( generator, block, state, node ) { const childState = Object.assign( {}, state, { parentNode: null }); - node.children.forEach( node => { - visit( generator, childBlock, childState, node ); + node.children.forEach( child => { + visit( generator, node._block, childState, child ); }); - - generator.addBlock( childBlock ); } export default function visitIfBlock ( generator, block, state, node ) { diff --git a/test/runtime/samples/component-yield-parent/_config.js b/test/runtime/samples/component-yield-parent/_config.js index cc3b39ca813c..b80ee68bdb2b 100644 --- a/test/runtime/samples/component-yield-parent/_config.js +++ b/test/runtime/samples/component-yield-parent/_config.js @@ -1,9 +1,15 @@ export default { - html: '

Hello

', + html: ` +

Hello

+ `, + test ( assert, component, target ) { assert.equal( component.get( 'data' ), 'Hello' ); - component.set({data: 'World'}); + + component.set({ data: 'World' }); assert.equal( component.get( 'data' ), 'World' ); - assert.equal( target.innerHTML, '

World

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

World

+ ` ); } }; From 950f2ce2fda65b16226f9f2152b2e29abdcba842 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 13:06:51 -0400 Subject: [PATCH 2/8] dont update static subtrees, even with a noop --- src/generators/Generator.js | 40 +++++- src/generators/dom/Block.js | 26 ++-- src/generators/dom/index.js | 9 +- src/generators/dom/preprocess.js | 48 ++++++-- src/generators/dom/visitors/EachBlock.js | 35 ++++-- src/generators/dom/visitors/IfBlock.js | 48 +++++--- .../samples/computed-collapsed-if/expected.js | 18 ++- .../each-block-changed-check/expected.js | 7 +- .../samples/event-handlers-custom/expected.js | 6 +- .../js/samples/if-block-no-update/expected.js | 115 ++++++++++++++++++ test/js/samples/if-block-no-update/input.html | 5 + 11 files changed, 287 insertions(+), 70 deletions(-) create mode 100644 test/js/samples/if-block-no-update/expected.js create mode 100644 test/js/samples/if-block-no-update/input.html diff --git a/src/generators/Generator.js b/src/generators/Generator.js index 5d7569be9d47..179cb2ee1501 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -73,7 +73,7 @@ export default class Generator { const { code, helpers } = this; const { contextDependencies, contexts, indexes } = block; - let scope = annotateWithScopes( expression ); + let scope = annotateWithScopes( expression ); // TODO this already happens in findDependencies let lexicalDepth = 0; const self = this; @@ -164,6 +164,44 @@ export default class Generator { return expression._contextualised; } + findDependencies ( block, expression, isEventHandler ) { + const dependencies = []; + + const { contextDependencies, contexts } = block; + + let scope = annotateWithScopes( expression ); + + walk( expression, { + enter ( node, parent ) { + if ( node._scope ) { + scope = node._scope; + return; + } + + if ( isReference( node, parent ) ) { + const { name } = flattenReference( node ); + if ( scope.has( name ) ) return; + + if ( name === 'event' && isEventHandler ) { + // noop + } else if ( contexts.has( name ) ) { + dependencies.push( ...contextDependencies.get( name ) ); + } else { + dependencies.push( name ); + } + + this.skip(); + } + }, + + leave ( node ) { + if ( node._scope ) scope = scope.parent; + } + }); + + return dependencies; + } + generate ( result, options, { name, format } ) { if ( this.imports.length ) { const statements = []; diff --git a/src/generators/dom/Block.js b/src/generators/dom/Block.js index 652262c51249..2982f05e0b84 100644 --- a/src/generators/dom/Block.js +++ b/src/generators/dom/Block.js @@ -34,6 +34,8 @@ export default class Block { // unique names this.component = this.getUniqueName( 'component' ); this.target = this.getUniqueName( 'target' ); + + this.hasUpdateMethod = false; // determined later } addDependencies ( dependencies ) { @@ -72,6 +74,10 @@ export default class Block { this.addElement( name, renderStatement, parentNode, true ); } + findDependencies ( expression, isEventHandler ) { + return this.generator.findDependencies( this, expression, isEventHandler ); + } + mount ( name, parentNode ) { if ( parentNode ) { this.builders.create.addLine( `${this.generator.helper( 'appendNode' )}( ${name}, ${parentNode} );` ); @@ -115,15 +121,17 @@ export default class Block { ` ); } - if ( this.builders.update.isEmpty() ) { - properties.addBlock( `update: ${this.generator.helper( 'noop' )},` ); - } else { - if ( this._tmp ) this.builders.update.addBlockAtStart( `var ${this._tmp};` ); - properties.addBlock( deindent` - update: function ( changed, ${this.params.join( ', ' )} ) { - ${this.builders.update} - }, - ` ); + if ( this.hasUpdateMethod ) { + if ( this.builders.update.isEmpty() ) { + properties.addBlock( `update: ${this.generator.helper( 'noop' )},` ); + } else { + if ( this._tmp ) this.builders.update.addBlockAtStart( `var ${this._tmp};` ); + properties.addBlock( deindent` + update: function ( changed, ${this.params.join( ', ' )} ) { + ${this.builders.update} + }, + ` ); + } } if ( this.builders.destroy.isEmpty() ) { diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 4c6e64ec23ed..2e2a17117ab0 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -107,12 +107,9 @@ export default function dom ( parsed, source, options ) { builders._set.addLine( `${generator.alias( 'recompute' )}( this._state, newState, oldState, false )` ); } - // TODO is the `if` necessary? - builders._set.addBlock( deindent` - ${generator.helper( 'dispatchObservers' )}( this, this._observers.pre, newState, oldState ); - if ( this._fragment ) this._fragment.update( newState, this._state ); - ${generator.helper( 'dispatchObservers' )}( this, this._observers.post, newState, oldState ); - ` ); + builders._set.addLine( `${generator.helper( 'dispatchObservers' )}( this, this._observers.pre, newState, oldState );` ); + if ( block.hasUpdateMethod ) builders._set.addLine( `if ( this._fragment ) this._fragment.update( newState, this._state );` ); // TODO is the condition necessary? + builders._set.addLine( `${generator.helper( 'dispatchObservers' )}( this, this._observers.post, newState, oldState );` ); if ( hasJs ) { builders.main.addBlock( `[✂${parsed.js.content.start}-${parsed.js.content.end}✂]` ); diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index 6a8ba20fe927..6c739ed3b822 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -6,22 +6,29 @@ function isElseIf ( node ) { const preprocessors = { MustacheTag: ( generator, block, node ) => { - const { dependencies } = block.contextualise( node.expression ); + const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); }, IfBlock: ( generator, block, node ) => { + const blocks = []; + let dynamic = false; + function attachBlocks ( node ) { - const { dependencies } = block.contextualise( node.expression ); + const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); node._block = block.child({ name: generator.getUniqueName( `create_if_block` ) }); - generator.blocks.push( node._block ); + blocks.push( node._block ); preprocessChildren( generator, node._block, node.children ); - block.addDependencies( node._block.dependencies ); + + if ( node._block.dependencies.size > 0 ) { + dynamic = true; + block.addDependencies( node._block.dependencies ); + } if ( isElseIf( node.else ) ) { attachBlocks( node.else.children[0] ); @@ -30,17 +37,27 @@ const preprocessors = { name: generator.getUniqueName( `create_if_block` ) }); - generator.blocks.push( node.else._block ); + blocks.push( node.else._block ); preprocessChildren( generator, node.else._block, node.else.children ); - block.addDependencies( node.else._block.dependencies ); + + if ( node.else._block.dependencies.size > 0 ) { + dynamic = true; + block.addDependencies( node.else._block.dependencies ); + } } } attachBlocks( node ); + + blocks.forEach( block => { + block.hasUpdateMethod = dynamic; + }); + + generator.blocks.push( ...blocks ); }, EachBlock: ( generator, block, node ) => { - const { dependencies } = block.contextualise( node.expression ); + const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); const indexNames = new Map( block.indexNames ); @@ -82,6 +99,7 @@ const preprocessors = { generator.blocks.push( node._block ); preprocessChildren( generator, node._block, node.children ); block.addDependencies( node._block.dependencies ); + node._block.hasUpdateMethod = node._block.dependencies.size > 0; if ( node.else ) { node.else._block = block.child({ @@ -90,6 +108,7 @@ const preprocessors = { generator.blocks.push( node.else._block ); preprocessChildren( generator, node.else._block, node.else.children ); + node.else._block.hasUpdateMethod = node.else._block.dependencies.size > 0; } }, @@ -98,16 +117,24 @@ const preprocessors = { if ( attribute.type === 'Attribute' && attribute.value !== true ) { attribute.value.forEach( chunk => { if ( chunk.type !== 'Text' ) { - const { dependencies } = block.contextualise( chunk.expression ); + const dependencies = block.findDependencies( chunk.expression ); block.addDependencies( dependencies ); } }); } else if ( attribute.type === 'Binding' ) { - const { dependencies } = block.contextualise( attribute.value ); + const dependencies = block.findDependencies( attribute.value ); block.addDependencies( dependencies ); } + + // else if ( attribute.type === 'EventHandler' ) { + // // TODO is this necessary? + // attribute.expression.arguments.forEach( arg => { + // const dependencies = block.findDependencies( arg ); + // block.addDependencies( dependencies ); + // }); + // } }); const isComponent = generator.components.has( node.name ) || node.name === ':Self'; @@ -121,6 +148,8 @@ const preprocessors = { generator.blocks.push( node._block ); preprocessChildren( generator, node._block, node.children ); + block.addDependencies( node._block.dependencies ); + node._block.hasUpdateMethod = node._block.dependencies.size > 0; } else { @@ -156,6 +185,7 @@ export default function preprocess ( generator, children ) { generator.blocks.push( block ); preprocessChildren( generator, block, children ); + block.hasUpdateMethod = block.dependencies.size > 0; return block; } \ No newline at end of file diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index 155797eb1edc..9f2b63b1802e 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -125,6 +125,13 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea } ` ); + const consequent = node._block.hasUpdateMethod ? + deindent` + ${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${lookup}[ ${key} ]; + ${_lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); + ` : + `${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${lookup}[ ${key} ];`; + block.builders.update.addBlock( deindent` var ${each_block_value} = ${snippet}; var ${_iterations} = []; @@ -138,8 +145,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea var ${key} = ${value}.${node.key}; if ( ${lookup}[ ${key} ] ) { - ${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${lookup}[ ${key} ]; - ${_lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); + ${consequent} } else { ${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}${node.key ? `, ${key}` : `` } ); } @@ -192,17 +198,28 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, .join( ' || ' ); if ( condition !== '' ) { + const forLoopBody = node._block.hasUpdateMethod ? + deindent` + if ( ${iterations}[${i}] ) { + ${iterations}[${i}].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); + } else { + ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); + ${iterations}[${i}].mount( ${anchor}.parentNode, ${anchor} ); + } + ` : + deindent` + ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); + ${iterations}[${i}].mount( ${anchor}.parentNode, ${anchor} ); + `; + + const start = node._block.hasUpdateMethod ? '0' : `${iterations}.length`; + block.builders.update.addBlock( deindent` var ${each_block_value} = ${snippet}; if ( ${condition} ) { - for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { - if ( !${iterations}[${i}] ) { - ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].mount( ${anchor}.parentNode, ${anchor} ); - } else { - ${iterations}[${i}].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); - } + for ( var ${i} = ${start}; ${i} < ${each_block_value}.length; ${i} += 1 ) { + ${forLoopBody} } ${generator.helper( 'destroyEach' )}( ${iterations}, true, ${each_block_value}.length ); diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index dab0d5b821ac..f0c5aaece39a 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -5,22 +5,24 @@ function isElseIf ( node ) { return node && node.children.length === 1 && node.children[0].type === 'IfBlock'; } -function getConditionsAndBlocks ( generator, block, state, node ) { - const conditionsAndBlocks = [{ +function getBranches ( generator, block, state, node ) { + const branches = [{ condition: block.contextualise( node.expression ).snippet, - block: node._block.name + block: node._block.name, + dynamic: node._block.dependencies.size > 0 }]; visitChildren( generator, block, state, node ); if ( isElseIf( node.else ) ) { - conditionsAndBlocks.push( - ...getConditionsAndBlocks( generator, block, state, node.else.children[0] ) + branches.push( + ...getBranches( generator, block, state, node.else.children[0] ) ); } else { - conditionsAndBlocks.push({ + branches.push({ condition: null, block: node.else ? node.else._block.name : null, + dynamic: node.else ? node.else._block.dependencies.size > 0 : false }); if ( node.else ) { @@ -28,7 +30,7 @@ function getConditionsAndBlocks ( generator, block, state, node ) { } } - return conditionsAndBlocks; + return branches; } function visitChildren ( generator, block, state, node ) { @@ -48,14 +50,15 @@ export default function visitIfBlock ( generator, block, state, node ) { const currentBlock = block.getUniqueName( `current_block` ); const _currentBlock = block.getUniqueName( `_current_block` ); - const conditionsAndBlocks = getConditionsAndBlocks( generator, block, state, node, generator.getUniqueName( `create_if_block` ) ); + const branches = getBranches( generator, block, state, node, generator.getUniqueName( `create_if_block` ) ); + const dynamic = branches.some( branch => branch.dynamic ); const anchor = `${name}_anchor`; block.createAnchor( anchor, state.parentNode ); block.builders.create.addBlock( deindent` function ${getBlock} ( ${params} ) { - ${conditionsAndBlocks.map( ({ condition, block }) => { + ${branches.map( ({ condition, block }) => { return `${condition ? `if ( ${condition} ) ` : ''}return ${block};`; } ).join( '\n' )} } @@ -75,15 +78,28 @@ export default function visitIfBlock ( generator, block, state, node ) { block.builders.update.addBlock( deindent` var ${_currentBlock} = ${currentBlock}; ${currentBlock} = ${getBlock}( ${params} ); - if ( ${_currentBlock} === ${currentBlock} && ${name}) { - ${name}.update( changed, ${params} ); - } else { - if ( ${name} ) ${name}.destroy( true ); - ${name} = ${currentBlock} && ${currentBlock}( ${params}, ${block.component} ); - if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); - } ` ); + if ( dynamic ) { + block.builders.update.addBlock( deindent` + if ( ${_currentBlock} === ${currentBlock} && ${name} ) { + ${name}.update( changed, ${params} ); + } else { + if ( ${name} ) ${name}.destroy( true ); + ${name} = ${currentBlock} && ${currentBlock}( ${params}, ${block.component} ); + if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); + } + ` ); + } else { + block.builders.update.addBlock( deindent` + if ( ${_currentBlock} !== ${currentBlock} ) { + if ( ${name} ) ${name}.destroy( true ); + ${name} = ${currentBlock} && ${currentBlock}( ${params}, ${block.component} ); + if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); + } + ` ); + } + block.builders.destroy.addLine( `if ( ${name} ) ${name}.destroy( ${isToplevel ? 'detach' : 'false'} );` ); diff --git a/test/js/samples/computed-collapsed-if/expected.js b/test/js/samples/computed-collapsed-if/expected.js index d8792a974f1b..50ca020f2b10 100644 --- a/test/js/samples/computed-collapsed-if/expected.js +++ b/test/js/samples/computed-collapsed-if/expected.js @@ -17,13 +17,11 @@ var template = (function () { }()); function create_main_fragment ( root, component ) { - + return { mount: noop, - - update: noop, - + destroy: noop }; } @@ -32,19 +30,19 @@ function SvelteComponent ( options ) { options = options || {}; this._state = options.data || {}; recompute( this._state, this._state, {}, true ); - + this._observers = { pre: Object.create( null ), post: Object.create( null ) }; - + this._handlers = Object.create( null ); - + this._root = options._root; this._yield = options._yield; - + this._torndown = false; - + this._fragment = create_main_fragment( this._state, this ); if ( options.target ) this._fragment.mount( options.target, null ); } @@ -55,9 +53,7 @@ SvelteComponent.prototype._set = function _set ( newState ) { var oldState = this._state; this._state = assign( {}, oldState, newState ); recompute( this._state, newState, oldState, false ) - dispatchObservers( this, this._observers.pre, newState, oldState ); - if ( this._fragment ) this._fragment.update( newState, this._state ); dispatchObservers( this, this._observers.post, newState, oldState ); }; diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 8b3edeb87ebc..d9ea165c62d4 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -23,11 +23,11 @@ function create_main_fragment ( root, component ) { if ( 'comments' in changed || 'elapsed' in changed || 'time' in changed ) { for ( var i = 0; i < each_block_value.length; i += 1 ) { - if ( !each_block_iterations[i] ) { + if ( each_block_iterations[i] ) { + each_block_iterations[i].update( changed, root, each_block_value, each_block_value[i], i ); + } else { each_block_iterations[i] = create_each_block( root, each_block_value, each_block_value[i], i, component ); each_block_iterations[i].mount( each_block_anchor.parentNode, each_block_anchor ); - } else { - each_block_iterations[i].update( changed, root, each_block_value, each_block_value[i], i ); } } @@ -127,7 +127,6 @@ assign( SvelteComponent.prototype, proto ); SvelteComponent.prototype._set = function _set ( newState ) { var oldState = this._state; this._state = assign( {}, oldState, newState ); - dispatchObservers( this, this._observers.pre, newState, oldState ); if ( this._fragment ) this._fragment.update( newState, this._state ); dispatchObservers( this, this._observers.post, newState, oldState ); diff --git a/test/js/samples/event-handlers-custom/expected.js b/test/js/samples/event-handlers-custom/expected.js index 5d4ae355a4e0..528bcfe5afb8 100644 --- a/test/js/samples/event-handlers-custom/expected.js +++ b/test/js/samples/event-handlers-custom/expected.js @@ -1,4 +1,4 @@ -import { appendNode, assign, createElement, createText, detachNode, dispatchObservers, insertNode, noop, proto } from "svelte/shared.js"; +import { appendNode, assign, createElement, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; var template = (function () { return { @@ -30,8 +30,6 @@ function create_main_fragment ( root, component ) { insertNode( button, target, anchor ); }, - update: noop, - destroy: function ( detach ) { foo_handler.teardown(); @@ -67,9 +65,7 @@ assign( SvelteComponent.prototype, template.methods, proto ); SvelteComponent.prototype._set = function _set ( newState ) { var oldState = this._state; this._state = assign( {}, oldState, newState ); - dispatchObservers( this, this._observers.pre, newState, oldState ); - if ( this._fragment ) this._fragment.update( newState, this._state ); dispatchObservers( this, this._observers.post, newState, oldState ); }; diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js new file mode 100644 index 000000000000..4409e6a2b1d1 --- /dev/null +++ b/test/js/samples/if-block-no-update/expected.js @@ -0,0 +1,115 @@ +import { appendNode, assign, createComment, createElement, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; + +function create_main_fragment ( root, component ) { + var if_block_anchor = createComment(); + + function get_block ( root ) { + if ( root.foo ) return create_if_block; + return create_if_block_1; + } + + var current_block = get_block( root ); + var if_block = current_block && current_block( root, component ); + + return { + mount: function ( target, anchor ) { + insertNode( if_block_anchor, target, anchor ); + if ( if_block ) if_block.mount( target, if_block_anchor ); + }, + + update: function ( changed, root ) { + var _current_block = current_block; + current_block = get_block( root ); + + if ( _current_block !== current_block ) { + if ( if_block ) if_block.destroy( true ); + if_block = current_block && current_block( root, component ); + if ( if_block ) if_block.mount( if_block_anchor.parentNode, if_block_anchor ); + } + }, + + destroy: function ( detach ) { + if ( if_block ) if_block.destroy( detach ); + + if ( detach ) { + detachNode( if_block_anchor ); + } + } + }; +} + +function create_if_block ( root, component ) { + var p = createElement( 'p' ); + appendNode( createText( "foo!" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function create_if_block_1 ( root, component ) { + var p = createElement( 'p' ); + appendNode( createText( "not foo!" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function SvelteComponent ( options ) { + options = options || {}; + this._state = options.data || {}; + + this._observers = { + pre: Object.create( null ), + post: Object.create( null ) + }; + + this._handlers = Object.create( null ); + + this._root = options._root; + this._yield = options._yield; + + this._torndown = false; + + this._fragment = create_main_fragment( this._state, this ); + if ( options.target ) this._fragment.mount( options.target, null ); +} + +assign( SvelteComponent.prototype, proto ); + +SvelteComponent.prototype._set = function _set ( newState ) { + var oldState = this._state; + this._state = assign( {}, oldState, newState ); + dispatchObservers( this, this._observers.pre, newState, oldState ); + if ( this._fragment ) this._fragment.update( newState, this._state ); + dispatchObservers( this, this._observers.post, newState, oldState ); +}; + +SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { + this.fire( 'destroy' ); + + this._fragment.destroy( detach !== false ); + this._fragment = null; + + this._state = {}; + this._torndown = true; +}; + +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/if-block-no-update/input.html b/test/js/samples/if-block-no-update/input.html new file mode 100644 index 000000000000..c73bfc624277 --- /dev/null +++ b/test/js/samples/if-block-no-update/input.html @@ -0,0 +1,5 @@ +{{#if foo}} +

foo!

+{{else}} +

not foo!

+{{/if}} \ No newline at end of file From 2e7a4296844b3662479f862c71fdfef05e013ea7 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 14:02:09 -0400 Subject: [PATCH 3/8] get rid of tmp variable, we dont need it --- src/generators/dom/Block.js | 5 ----- src/generators/dom/visitors/Element/Attribute.js | 3 +-- src/generators/dom/visitors/MustacheTag.js | 4 ++-- src/generators/dom/visitors/RawMustacheTag.js | 3 +-- .../js/samples/each-block-changed-check/expected.js | 13 +++++-------- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/generators/dom/Block.js b/src/generators/dom/Block.js index 2982f05e0b84..45df24c63c85 100644 --- a/src/generators/dom/Block.js +++ b/src/generators/dom/Block.js @@ -154,9 +154,4 @@ export default class Block { } `; } - - tmp () { - if ( !this._tmp ) this._tmp = this.getUniqueName( 'tmp' ); - return this._tmp; - } } \ No newline at end of file diff --git a/src/generators/dom/visitors/Element/Attribute.js b/src/generators/dom/visitors/Element/Attribute.js index 3b9a3cc2999f..9addde05efc4 100644 --- a/src/generators/dom/visitors/Element/Attribute.js +++ b/src/generators/dom/visitors/Element/Attribute.js @@ -81,8 +81,7 @@ export default function visitAttribute ( generator, block, state, node, attribut block.builders.create.addLine( updater ); block.builders.update.addBlock( deindent` - if ( ( ${block.tmp()} = ${value} ) !== ${last} ) { - ${last} = ${block.tmp()}; + if ( ${last} !== ( ${last} = ${value} ) ) { ${updater} } ` ); diff --git a/src/generators/dom/visitors/MustacheTag.js b/src/generators/dom/visitors/MustacheTag.js index 60e64e1f8ea6..33fe569e88c0 100644 --- a/src/generators/dom/visitors/MustacheTag.js +++ b/src/generators/dom/visitors/MustacheTag.js @@ -9,8 +9,8 @@ export default function visitMustacheTag ( generator, block, state, node ) { block.addElement( name, `${generator.helper( 'createText' )}( last_${name} )`, state.parentNode, true ); block.builders.update.addBlock( deindent` - if ( ( ${block.tmp()} = ${snippet} ) !== last_${name} ) { - ${name}.data = last_${name} = ${block.tmp()}; + if ( last_${name} !== ( last_${name} = ${snippet} ) ) { + ${name}.data = last_${name}; } ` ); } \ No newline at end of file diff --git a/src/generators/dom/visitors/RawMustacheTag.js b/src/generators/dom/visitors/RawMustacheTag.js index a99d7cba8f4c..e0dc76e9f852 100644 --- a/src/generators/dom/visitors/RawMustacheTag.js +++ b/src/generators/dom/visitors/RawMustacheTag.js @@ -26,8 +26,7 @@ export default function visitRawMustacheTag ( generator, block, state, node ) { } block.builders.update.addBlock( deindent` - if ( ( ${block.tmp()} = ${snippet} ) !== last_${name} ) { - last_${name} = ${block.tmp()}; + if ( last_${name} !== ( last_${name} = ${snippet} ) ) { ${detachStatement} ${mountStatement} } diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index d9ea165c62d4..0693c6f32002 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -75,18 +75,15 @@ function create_each_block ( root, each_block_value, comment, comment_index, com }, update: function ( changed, root, each_block_value, comment, comment_index ) { - var tmp; - - if ( ( tmp = comment.author ) !== last_text ) { - text.data = last_text = tmp; + if ( last_text !== ( last_text = comment.author ) ) { + text.data = last_text; } - if ( ( tmp = root.elapsed(comment.time, root.time) ) !== last_text_2 ) { - text_2.data = last_text_2 = tmp; + if ( last_text_2 !== ( last_text_2 = root.elapsed(comment.time, root.time) ) ) { + text_2.data = last_text_2; } - if ( ( tmp = comment.html ) !== last_raw ) { - last_raw = tmp; + if ( last_raw !== ( last_raw = comment.html ) ) { detachBetween( raw_before, raw_after ); raw_before.insertAdjacentHTML( 'afterend', last_raw ); } From c9a2bf98a5a4624fe6c61424ca4b29fc9ac8bce2 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 14:26:09 -0400 Subject: [PATCH 4/8] rename some variables so that they make more sense --- .../dom/visitors/Element/Attribute.js | 2 +- src/generators/dom/visitors/MustacheTag.js | 9 +++---- src/generators/dom/visitors/RawMustacheTag.js | 12 +++++----- .../each-block-changed-check/expected.js | 24 +++++++++---------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/generators/dom/visitors/Element/Attribute.js b/src/generators/dom/visitors/Element/Attribute.js index 9addde05efc4..8dd976d406fd 100644 --- a/src/generators/dom/visitors/Element/Attribute.js +++ b/src/generators/dom/visitors/Element/Attribute.js @@ -43,7 +43,7 @@ export default function visitAttribute ( generator, block, state, node, attribut ); } - const last = `last_${state.parentNode}_${name.replace( /[^a-zA-Z_$]/g, '_')}`; + const last = block.getUniqueName( `${state.parentNode}_${name.replace( /[^a-zA-Z_$]/g, '_')}_value` ); block.builders.create.addLine( `var ${last} = ${value};` ); const isSelectValueAttribute = name === 'value' && state.parentNodeName === 'select'; diff --git a/src/generators/dom/visitors/MustacheTag.js b/src/generators/dom/visitors/MustacheTag.js index 33fe569e88c0..301345e6cc0a 100644 --- a/src/generators/dom/visitors/MustacheTag.js +++ b/src/generators/dom/visitors/MustacheTag.js @@ -2,15 +2,16 @@ import deindent from '../../../utils/deindent.js'; export default function visitMustacheTag ( generator, block, state, node ) { const name = block.getUniqueName( 'text' ); + const value = block.getUniqueName( `${name}_value` ); const { snippet } = block.contextualise( node.expression ); - block.builders.create.addLine( `var last_${name} = ${snippet};` ); - block.addElement( name, `${generator.helper( 'createText' )}( last_${name} )`, state.parentNode, true ); + block.builders.create.addLine( `var ${value} = ${snippet};` ); + block.addElement( name, `${generator.helper( 'createText' )}( ${value} )`, state.parentNode, true ); block.builders.update.addBlock( deindent` - if ( last_${name} !== ( last_${name} = ${snippet} ) ) { - ${name}.data = last_${name}; + if ( ${value} !== ( ${value} = ${snippet} ) ) { + ${name}.data = ${value}; } ` ); } \ No newline at end of file diff --git a/src/generators/dom/visitors/RawMustacheTag.js b/src/generators/dom/visitors/RawMustacheTag.js index e0dc76e9f852..2eed5bfdb6cf 100644 --- a/src/generators/dom/visitors/RawMustacheTag.js +++ b/src/generators/dom/visitors/RawMustacheTag.js @@ -2,21 +2,21 @@ import deindent from '../../../utils/deindent.js'; export default function visitRawMustacheTag ( generator, block, state, node ) { const name = block.getUniqueName( 'raw' ); + const value = block.getUniqueName( `${name}_value` ); + const before = block.getUniqueName( `${name}_before` ); + const after = block.getUniqueName( `${name}_after` ); const { snippet } = block.contextualise( node.expression ); // we would have used comments here, but the `insertAdjacentHTML` api only // exists for `Element`s. - const before = `${name}_before`; block.addElement( before, `${generator.helper( 'createElement' )}( 'noscript' )`, state.parentNode, true ); - - const after = `${name}_after`; block.addElement( after, `${generator.helper( 'createElement' )}( 'noscript' )`, state.parentNode, true ); const isToplevel = !state.parentNode; - block.builders.create.addLine( `var last_${name} = ${snippet};` ); - const mountStatement = `${before}.insertAdjacentHTML( 'afterend', last_${name} );`; + block.builders.create.addLine( `var ${value} = ${snippet};` ); + const mountStatement = `${before}.insertAdjacentHTML( 'afterend', ${value} );`; const detachStatement = `${generator.helper( 'detachBetween' )}( ${before}, ${after} );`; if ( isToplevel ) { @@ -26,7 +26,7 @@ export default function visitRawMustacheTag ( generator, block, state, node ) { } block.builders.update.addBlock( deindent` - if ( last_${name} !== ( last_${name} = ${snippet} ) ) { + if ( ${value} !== ( ${value} = ${snippet} ) ) { ${detachStatement} ${mountStatement} } diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index 0693c6f32002..537390d43184 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -53,12 +53,12 @@ function create_each_block ( root, each_block_value, comment, comment_index, com var span = createElement( 'span' ); appendNode( span, div ); span.className = "meta"; - var last_text = comment.author; - var text = createText( last_text ); + var text_value = comment.author; + var text = createText( text_value ); appendNode( text, span ); appendNode( createText( " wrote " ), span ); - var last_text_2 = root.elapsed(comment.time, root.time); - var text_2 = createText( last_text_2 ); + var text_2_value = root.elapsed(comment.time, root.time); + var text_2 = createText( text_2_value ); appendNode( text_2, span ); appendNode( createText( " ago:" ), span ); appendNode( createText( "\n\n\t\t" ), div ); @@ -66,8 +66,8 @@ function create_each_block ( root, each_block_value, comment, comment_index, com appendNode( raw_before, div ); var raw_after = createElement( 'noscript' ); appendNode( raw_after, div ); - var last_raw = comment.html; - raw_before.insertAdjacentHTML( 'afterend', last_raw ); + var raw_value = comment.html; + raw_before.insertAdjacentHTML( 'afterend', raw_value ); return { mount: function ( target, anchor ) { @@ -75,17 +75,17 @@ function create_each_block ( root, each_block_value, comment, comment_index, com }, update: function ( changed, root, each_block_value, comment, comment_index ) { - if ( last_text !== ( last_text = comment.author ) ) { - text.data = last_text; + if ( text_value !== ( text_value = comment.author ) ) { + text.data = text_value; } - if ( last_text_2 !== ( last_text_2 = root.elapsed(comment.time, root.time) ) ) { - text_2.data = last_text_2; + if ( text_2_value !== ( text_2_value = root.elapsed(comment.time, root.time) ) ) { + text_2.data = text_2_value; } - if ( last_raw !== ( last_raw = comment.html ) ) { + if ( raw_value !== ( raw_value = comment.html ) ) { detachBetween( raw_before, raw_after ); - raw_before.insertAdjacentHTML( 'afterend', last_raw ); + raw_before.insertAdjacentHTML( 'afterend', raw_value ); } }, From f8f32a13ba2309f7d0615d6cbb8fd411c92b8083 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 14:39:03 -0400 Subject: [PATCH 5/8] contextualise is only called once per expression --- src/generators/Generator.js | 6 +----- src/generators/dom/visitors/EachBlock.js | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/generators/Generator.js b/src/generators/Generator.js index 179cb2ee1501..b39c9d752b2e 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -63,8 +63,6 @@ export default class Generator { } contextualise ( block, expression, context, isEventHandler ) { - if ( expression._contextualised ) return expression._contextualised; - this.addSourcemapLocations( expression ); const usedContexts = []; @@ -155,13 +153,11 @@ export default class Generator { } }); - expression._contextualised = { + return { dependencies, contexts: usedContexts, snippet: `[✂${expression.start}-${expression.end}✂]` }; - - return expression._contextualised; } findDependencies ( block, expression, isEventHandler ) { diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index 9f2b63b1802e..770de7323534 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -187,7 +187,7 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, } ` ); - const { dependencies } = block.contextualise( node.expression ); + const dependencies = block.findDependencies( node.expression ); const allDependencies = new Set( block.dependencies ); dependencies.forEach( dependency => { allDependencies.add( dependency ); From 49bea1b489b3725d44c43fb9aebb3cd139947fa7 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 14:51:05 -0400 Subject: [PATCH 6/8] dont recompute dependencies --- src/generators/Generator.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/generators/Generator.js b/src/generators/Generator.js index b39c9d752b2e..1bf2b7c111d6 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -66,10 +66,9 @@ export default class Generator { this.addSourcemapLocations( expression ); const usedContexts = []; - const dependencies = []; const { code, helpers } = this; - const { contextDependencies, contexts, indexes } = block; + const { contexts, indexes } = block; let scope = annotateWithScopes( expression ); // TODO this already happens in findDependencies let lexicalDepth = 0; @@ -108,7 +107,6 @@ export default class Generator { code.overwrite( node.start, node.start + name.length, contextName, true ); } - dependencies.push( ...contextDependencies.get( name ) ); if ( !~usedContexts.indexOf( name ) ) usedContexts.push( name ); } @@ -133,7 +131,6 @@ export default class Generator { code.prependRight( node.start, `root.` ); } - dependencies.push( name ); if ( !~usedContexts.indexOf( 'root' ) ) usedContexts.push( 'root' ); } @@ -147,22 +144,17 @@ export default class Generator { } }); - dependencies.forEach( name => { - if ( !globalWhitelist.has( name ) ) { - this.expectedProperties.add( name ); - } - }); - return { - dependencies, + dependencies: expression._dependencies, // TODO probably a better way to do this contexts: usedContexts, snippet: `[✂${expression.start}-${expression.end}✂]` }; } findDependencies ( block, expression, isEventHandler ) { - const dependencies = []; + if ( expression._dependencies ) return expression._dependencies; + const dependencies = []; const { contextDependencies, contexts } = block; let scope = annotateWithScopes( expression ); @@ -195,7 +187,13 @@ export default class Generator { } }); - return dependencies; + dependencies.forEach( name => { + if ( !globalWhitelist.has( name ) ) { + this.expectedProperties.add( name ); + } + }); + + return ( expression._dependencies = dependencies ); } generate ( result, options, { name, format } ) { From b7a40879a77315ef2b29e934444683d4c9318abd Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 14:55:42 -0400 Subject: [PATCH 7/8] remove some unused code --- src/generators/Generator.js | 10 +++------- src/generators/dom/Block.js | 4 ++-- src/generators/dom/preprocess.js | 9 +-------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/generators/Generator.js b/src/generators/Generator.js index 1bf2b7c111d6..8d43de8bf862 100644 --- a/src/generators/Generator.js +++ b/src/generators/Generator.js @@ -151,13 +151,11 @@ export default class Generator { }; } - findDependencies ( block, expression, isEventHandler ) { + findDependencies ( contextDependencies, expression ) { if ( expression._dependencies ) return expression._dependencies; - const dependencies = []; - const { contextDependencies, contexts } = block; - let scope = annotateWithScopes( expression ); + const dependencies = []; walk( expression, { enter ( node, parent ) { @@ -170,9 +168,7 @@ export default class Generator { const { name } = flattenReference( node ); if ( scope.has( name ) ) return; - if ( name === 'event' && isEventHandler ) { - // noop - } else if ( contexts.has( name ) ) { + if ( contextDependencies.has( name ) ) { dependencies.push( ...contextDependencies.get( name ) ); } else { dependencies.push( name ); diff --git a/src/generators/dom/Block.js b/src/generators/dom/Block.js index 45df24c63c85..11889070fab9 100644 --- a/src/generators/dom/Block.js +++ b/src/generators/dom/Block.js @@ -74,8 +74,8 @@ export default class Block { this.addElement( name, renderStatement, parentNode, true ); } - findDependencies ( expression, isEventHandler ) { - return this.generator.findDependencies( this, expression, isEventHandler ); + findDependencies ( expression ) { + return this.generator.findDependencies( this.contextDependencies, expression ); } mount ( name, parentNode ) { diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index 6c739ed3b822..bc23543b3fbe 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -127,14 +127,6 @@ const preprocessors = { const dependencies = block.findDependencies( attribute.value ); block.addDependencies( dependencies ); } - - // else if ( attribute.type === 'EventHandler' ) { - // // TODO is this necessary? - // attribute.expression.arguments.forEach( arg => { - // const dependencies = block.findDependencies( arg ); - // block.addDependencies( dependencies ); - // }); - // } }); const isComponent = generator.components.has( node.name ) || node.name === ':Self'; @@ -175,6 +167,7 @@ export default function preprocess ( generator, children ) { contexts: new Map(), indexes: new Map(), + contextDependencies: new Map(), params: [ 'root' ], indexNames: new Map(), From 080afc99a868b30249e657831390e4208148277f Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 17 Apr 2017 15:05:48 -0400 Subject: [PATCH 8/8] simplify if-block switching code --- src/generators/dom/visitors/IfBlock.js | 20 +++++++------------ .../js/samples/if-block-no-update/expected.js | 5 +---- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index f0c5aaece39a..be96352edf39 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -47,8 +47,7 @@ export default function visitIfBlock ( generator, block, state, node ) { const params = block.params.join( ', ' ); const name = generator.getUniqueName( `if_block` ); const getBlock = block.getUniqueName( `get_block` ); - const currentBlock = block.getUniqueName( `current_block` ); - const _currentBlock = block.getUniqueName( `_current_block` ); + const current_block = block.getUniqueName( `current_block` ); const branches = getBranches( generator, block, state, node, generator.getUniqueName( `create_if_block` ) ); const dynamic = branches.some( branch => branch.dynamic ); @@ -63,8 +62,8 @@ export default function visitIfBlock ( generator, block, state, node ) { } ).join( '\n' )} } - var ${currentBlock} = ${getBlock}( ${params} ); - var ${name} = ${currentBlock} && ${currentBlock}( ${params}, ${block.component} ); + var ${current_block} = ${getBlock}( ${params} ); + var ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); ` ); const isToplevel = !state.parentNode; @@ -75,26 +74,21 @@ export default function visitIfBlock ( generator, block, state, node ) { block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, ${anchor} );` ); } - block.builders.update.addBlock( deindent` - var ${_currentBlock} = ${currentBlock}; - ${currentBlock} = ${getBlock}( ${params} ); - ` ); - if ( dynamic ) { block.builders.update.addBlock( deindent` - if ( ${_currentBlock} === ${currentBlock} && ${name} ) { + if ( ${current_block} === ( ${current_block} = ${getBlock}( ${params} ) ) && ${name} ) { ${name}.update( changed, ${params} ); } else { if ( ${name} ) ${name}.destroy( true ); - ${name} = ${currentBlock} && ${currentBlock}( ${params}, ${block.component} ); + ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); } ` ); } else { block.builders.update.addBlock( deindent` - if ( ${_currentBlock} !== ${currentBlock} ) { + if ( ${current_block} !== ( ${current_block} = ${getBlock}( ${params} ) ) ) { if ( ${name} ) ${name}.destroy( true ); - ${name} = ${currentBlock} && ${currentBlock}( ${params}, ${block.component} ); + ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); } ` ); diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index 4409e6a2b1d1..f0fbc2b6d597 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -18,10 +18,7 @@ function create_main_fragment ( root, component ) { }, update: function ( changed, root ) { - var _current_block = current_block; - current_block = get_block( root ); - - if ( _current_block !== current_block ) { + if ( current_block !== ( current_block = get_block( root ) ) ) { if ( if_block ) if_block.destroy( true ); if_block = current_block && current_block( root, component ); if ( if_block ) if_block.mount( if_block_anchor.parentNode, if_block_anchor );