Fixes #508 - Bugs in the static sub-tree optimization for VDOM compilation

This commit is contained in:
Patrick Steele-Idem 2017-01-05 11:05:22 -07:00
parent 0d7839c533
commit 29d7482c90
4 changed files with 81 additions and 14 deletions

View File

@ -21,12 +21,37 @@ c) Else, generate one of the following:
*/
const Node = require('../../ast/Node');
const nextConstIdFuncSymbol = Symbol();
const OPTIMIZER_CONTEXT_KEY = Symbol();
const OPTIONS_DEFAULT = { optimizeTextNodes: true, optimizeStaticNodes: true };
const OPTIONS_OPTIMIZE_TEXT_NODES = { optimizeTextNodes: true, optimizeStaticNodes: false };
class OptimizerContext {
constructor(context) {
this.context = context;
this.nextAttrsId = 0;
this.nextNodeId = 0;
this._nextConstIdFunc = null;
}
get nextConstIdFunc() {
let nextConstIdFunc = this._nextConstIdFunc;
if (!nextConstIdFunc) {
let context = this.context;
let builder = context.builder;
let constId = this.context.helper('const');
let fingerprintLiteral = builder.literal(context.getFingerprint(6));
nextConstIdFunc = this._nextConstIdFunc = context.addStaticVar(
'marko_const_nextId',
builder.functionCall(constId, [ fingerprintLiteral ]));
}
return nextConstIdFunc;
}
}
class NodeVDOM extends Node {
constructor(variableIdentifier) {
super('NodeVDOM');
@ -54,8 +79,10 @@ class NodeVDOM extends Node {
function generateNodesForArray(nodes, context, options) {
let builder = context.builder;
let nextNodeId = 0;
let nextAttrsId = 0;
var optimizerContext = context[OPTIMIZER_CONTEXT_KEY] ||
(context[OPTIMIZER_CONTEXT_KEY] = new OptimizerContext(context));
var optimizeStaticNodes = options.optimizeStaticNodes !== false;
@ -66,17 +93,10 @@ function generateNodesForArray(nodes, context, options) {
node.createTextId = context.importModule('marko_createText', 'marko/vdom/createText');
}*/
let nextConstIdFunc = context.data[nextConstIdFuncSymbol];
if (!nextConstIdFunc) {
let constId = context.helper('const');
let fingerprintLiteral = builder.literal(context.getFingerprint(6));
nextConstIdFunc = context.data[nextConstIdFuncSymbol] = context.addStaticVar('marko_const_nextId', builder.functionCall(constId, [ fingerprintLiteral ]));
}
node.nextConstId = builder.functionCall(nextConstIdFunc, []);
node.nextConstId = builder.functionCall(optimizerContext.nextConstIdFunc, []);
node.isStaticRoot = true;
let staticNodeId = context.addStaticVar('marko_node' + (nextNodeId++), node);
let staticNodeId = context.addStaticVar('marko_node' + (optimizerContext.nextNodeId++), node);
return new NodeVDOM(staticNodeId);
}
@ -85,7 +105,7 @@ function generateNodesForArray(nodes, context, options) {
var attributesArg = node.attributesArg;
if (attributesArg) {
node.isStaticRoot = true;
let staticAttrsId = context.addStaticVar('marko_attrs' + (nextAttrsId++), attributesArg);
let staticAttrsId = context.addStaticVar('marko_attrs' + (optimizerContext.nextAttrsId++), attributesArg);
node.attributesArg = staticAttrsId;
}
}

View File

@ -5,6 +5,8 @@ var marko_template = module.exports = require("marko/vdom").t(),
marko_const = marko_helpers.const,
marko_const_nextId = marko_const("6597f2"),
marko_node0 = marko_createElement("div", null, 1, marko_const_nextId())
.t("No colors!"),
marko_node1 = marko_createElement("div", null, 1, marko_const_nextId())
.t("No colors!");
function render(data, out) {
@ -37,7 +39,7 @@ function render(data, out) {
out.ee();
} else {
out.n(marko_node0);
out.n(marko_node1);
}
}

View File

@ -0,0 +1 @@
<div id="prodHolder"><div class="A"><div class="B">yes</div><div class="C"></div><div class="C"></div></div><div class="D"><div class="E"><div class="F"><div class="G">yes</div><div class="H">H-yes</div></div><div class="I"><div class="J">yes</div></div></div><div class="K"><div class="L"><div class="M"><div class="N">yes</div></div></div><div class="O">yes</div><div class="P">P-yes</div></div><div class="Q">Q-body: This div should have a class of Q</div></div></div>

View File

@ -0,0 +1,44 @@
<div id="prodHolder">
<div class="A">
<div class="B">
${true ? 'yes' : 'no'}
</div>
<div class="C" for(var i=0;i<2;i++)>
</div>
</div>
<div class="D">
<div class="E">
<div class="F">
<div class="G">
${true ? 'yes' : 'no'}
</div>
<div class="H">
${true ? 'H-yes' : 'H-no'}
</div>
</div>
<div class="I">
<if(1 > 0)>
<div class="J">${true ? 'yes' : 'no'}</div>
</if>
</div>
</div>
<div class="K">
<div class="L">
<div class="M">
<div class="N">
$!{true ? 'yes' : 'no'}
</div>
</div>
</div>
<div class="O">
${true ? 'yes' : 'no'}
</div>
<div class="P">
${true ? 'P-yes' : 'P-no'}
</div>
</div>
<div class="Q">
Q-body: ${true ? 'This div should have a class of Q' : 'no'}
</div>
</div>
</div>