marko
Version:
UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.
168 lines (143 loc) • 4.55 kB
JavaScript
;var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");exports.__esModule = true;exports.analyzeStaticVDOM = analyzeStaticVDOM;exports.optimizeStaticVDOM = optimizeStaticVDOM;var _compiler = require("@marko/compiler");
var _babelUtils = require("@marko/compiler/babel-utils");
var _he = require("he");
var _attributes = _interopRequireDefault(require("../tag/native-tag[vdom]/attributes"));
var _keyManager = require("./key-manager");
var _vdomOutWrite = _interopRequireDefault(require("./vdom-out-write"));
const skipDirectives = new Set([
"key",
"w-bind",
"no-update",
"no-update-if",
"no-update-body",
"no-update-body-if"]
);
const staticNodes = new WeakSet();
const mergeStaticCreateVisitor = {
MarkoText(path, state) {
const { node } = path;
state.currentRoot = _compiler.types.callExpression(
_compiler.types.memberExpression(state.currentRoot, _compiler.types.identifier("t")),
[_compiler.types.stringLiteral((0, _he.decode)(node.value))]
);
},
MarkoPlaceholder(path, state) {
const computed = (0, _babelUtils.computeNode)(path.node.value);
state.currentRoot = _compiler.types.callExpression(
_compiler.types.memberExpression(state.currentRoot, _compiler.types.identifier("t")),
[
_compiler.types.stringLiteral(
computed && computed.value != null ? `${computed.value}` : ""
)]
);
},
MarkoTag(path, state) {
(0, _keyManager.getKeyManager)(path).resolveKey(path);
state.currentRoot = _compiler.types.callExpression(
_compiler.types.memberExpression(state.currentRoot, _compiler.types.identifier("e")),
getConstElementArgs(path)
);
}
};
const analyzeStaticVisitor = {
MarkoText(path) {
staticNodes.add(path.node);
},
MarkoPlaceholder(path) {
if (path.node.escape) {
const computed = (0, _babelUtils.computeNode)(path.node.value);
if (computed) {
staticNodes.add(path.node);
}
}
},
MarkoTag: {
enter(path) {
// needed to handle global keys on elements that don't have specific key attributes
if ((0, _babelUtils.isLoopTag)(path)) path.skip();
},
exit(path) {
// check name
let isStatic =
(0, _babelUtils.isNativeTag)(path) &&
!path.node.attributeTags.length &&
!path.node.body.attributeTags &&
!path.node.body.params.length &&
!path.node.arguments &&
!(0, _keyManager.hasUserKey)(path);
const tagDef = (0, _babelUtils.getTagDef)(path);
isStatic =
isStatic && (
!tagDef.translator ||
tagDef.name === "script" ||
tagDef.name === "style");
// check attributes
isStatic =
isStatic &&
path.
get("attributes").
every(
(attr) =>
_compiler.types.isMarkoAttribute(attr) &&
!(
attr.node.arguments ||
attr.node.modifier ||
skipDirectives.has(attr.node.name) ||
!(0, _babelUtils.computeNode)(attr.node.value))
);
// check children
isStatic =
isStatic &&
path.
get("body").
get("body").
every((t) => staticNodes.has(t.node));
if (isStatic) staticNodes.add(path.node);
}
}
};
function optimizeStaticVDOM(path) {
const {
hub: { file }
} = path;
if (
!shouldRun(file.markoOpts) ||
!staticNodes.has(path.node) ||
staticNodes.has(path.parentPath.parentPath.node))
{
return;
}
const identifier = path.scope.generateUidIdentifier("marko_node");
const state = {
currentRoot: _compiler.types.callExpression(
(0, _babelUtils.importDefault)(
file,
"marko/src/runtime/vdom/helpers/const-element.js",
"marko_constElement"
),
getConstElementArgs(path)
)
};
path.traverse(mergeStaticCreateVisitor, state);
const d = _compiler.types.variableDeclaration("const", [
_compiler.types.variableDeclarator(identifier, state.currentRoot)]
);
file.path.node.body.push(d);
path.replaceWith((0, _vdomOutWrite.default)("n", identifier, file._componentInstanceIdentifier));
path.skip();
}
function analyzeStaticVDOM(path) {
if (shouldRun(path.hub.file.markoOpts)) {
path.traverse(analyzeStaticVisitor);
}
}
function shouldRun(markoOpts) {
return markoOpts.optimize && markoOpts.output !== "html";
}
function getConstElementArgs(path) {
const { node } = path;
return [
node.name,
(0, _attributes.default)(path, path.get("attributes")),
_compiler.types.numericLiteral(node.body.body.length)];
}