mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
140 lines
3.8 KiB
JavaScript
140 lines
3.8 KiB
JavaScript
'use strict';
|
|
|
|
/*
|
|
Algorithm:
|
|
|
|
Walk the DOM tree to find all HtmlElementVDOM and TextVDOM nodes
|
|
|
|
a) If a node is static then move to a static variable. Depending on whether or not the node is a root or nested,
|
|
we will need to replace it with one of the following:
|
|
- out.n(staticVar)
|
|
- .n(staticVar)
|
|
|
|
b) If a node is HTML-only then generate code depending on if it is root or not:
|
|
|
|
- out.e('div', ...) | out.t('foo')
|
|
- .e('div', ...) || .t('foo')
|
|
|
|
c) Else, generate one of the following:
|
|
|
|
- out.beginElement()
|
|
|
|
*/
|
|
|
|
const Node = require('../../ast/Node');
|
|
const nextConstIdFuncSymbol = Symbol();
|
|
|
|
const OPTIONS_DEFAULT = { optimizeTextNodes: true, optimizeStaticNodes: true };
|
|
const OPTIONS_OPTIMIZE_TEXT_NODES = { optimizeTextNodes: true, optimizeStaticNodes: false };
|
|
|
|
class NodeVDOM extends Node {
|
|
constructor(variableIdentifier) {
|
|
super('NodeVDOM');
|
|
this.variableIdentifier = variableIdentifier;
|
|
}
|
|
|
|
writeCode(writer) {
|
|
var builder = writer.builder;
|
|
|
|
let funcCall = builder.functionCall(
|
|
builder.identifier('n'),
|
|
[
|
|
this.variableIdentifier
|
|
]);
|
|
|
|
if (this.isChild) {
|
|
writer.write('.');
|
|
} else {
|
|
writer.write('out.');
|
|
}
|
|
|
|
writer.write(funcCall);
|
|
}
|
|
}
|
|
|
|
function generateNodesForArray(nodes, context, options) {
|
|
let builder = context.builder;
|
|
let nextNodeId = 0;
|
|
let nextAttrsId = 0;
|
|
|
|
var optimizeStaticNodes = options.optimizeStaticNodes !== false;
|
|
|
|
function generateStaticNode(node) {
|
|
if (node.type === 'HtmlElementVDOM') {
|
|
node.createElementId = context.helper('createElement');
|
|
}/* else {
|
|
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.isStaticRoot = true;
|
|
let staticNodeId = context.addStaticVar('marko_node' + (nextNodeId++), node);
|
|
|
|
return new NodeVDOM(staticNodeId);
|
|
}
|
|
|
|
function handleStaticAttributes(node) {
|
|
var attributesArg = node.attributesArg;
|
|
if (attributesArg) {
|
|
node.isStaticRoot = true;
|
|
let staticAttrsId = context.addStaticVar('marko_attrs' + (nextAttrsId++), attributesArg);
|
|
node.attributesArg = staticAttrsId;
|
|
}
|
|
}
|
|
|
|
let finalNodes = [];
|
|
let i = 0;
|
|
|
|
while (i<nodes.length) {
|
|
let node = nodes[i];
|
|
if (node.type === 'HtmlElementVDOM') {
|
|
if (optimizeStaticNodes) {
|
|
if (node.isStatic) {
|
|
finalNodes.push(generateStaticNode(node));
|
|
doOptimizeNode(node, context, OPTIONS_OPTIMIZE_TEXT_NODES);
|
|
} else {
|
|
if (node.isAttrsStatic) {
|
|
handleStaticAttributes(node);
|
|
}
|
|
|
|
finalNodes.push(node);
|
|
}
|
|
} else {
|
|
finalNodes.push(node);
|
|
}
|
|
|
|
} else {
|
|
finalNodes.push(node);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return finalNodes;
|
|
}
|
|
|
|
function doOptimizeNode(node, context, options) {
|
|
let walker = context.createWalker({
|
|
enterArray(nodes) {
|
|
return generateNodesForArray(nodes, context, options);
|
|
}
|
|
});
|
|
|
|
return walker.walk(node);
|
|
}
|
|
|
|
class VDOMOptimizer {
|
|
optimize(node, context) {
|
|
doOptimizeNode(node, context, OPTIONS_DEFAULT);
|
|
}
|
|
}
|
|
|
|
module.exports = VDOMOptimizer; |