resultCache: Map<TemplateChildNode, boolean>,
doNotHoistNode: boolean = false
) {
+ let hasHoistedNode = false
for (let i = 0; i < children.length; i++) {
const child = children[i]
// only plain elements & text calls are eligible for hoisting.
;(child.codegenNode as VNodeCall).patchFlag =
PatchFlags.HOISTED + (__DEV__ ? ` /* HOISTED */` : ``)
child.codegenNode = context.hoist(child.codegenNode!)
+ hasHoistedNode = true
continue
} else {
// node may contain dynamic children, but its props may be eligible for
isStaticNode(child.content, resultCache)
) {
child.codegenNode = context.hoist(child.codegenNode)
+ hasHoistedNode = true
}
// walk further
}
}
- if (context.transformHoist) {
+ if (hasHoistedNode && context.transformHoist) {
context.transformHoist(children, context)
}
}
type StringiableNode = PlainElementNode | TextCallNode
-// Turn eligible hoisted static trees into stringied static nodes, e.g.
-// const _hoisted_1 = createStaticVNode(`<div class="foo">bar</div>`)
-// This is only performed in non-in-browser compilations.
+/**
+ * Turn eligible hoisted static trees into stringied static nodes, e.g.
+ *
+ * ```js
+ * const _hoisted_1 = createStaticVNode(`<div class="foo">bar</div>`)
+ * ```
+ *
+ * A single static vnode can contain stringified content for **multiple**
+ * consecutive nodes (element and plain text), called a "chunk".
+ * `@vue/runtime-dom` will create the content via innerHTML in a hidden
+ * container element and insert all the nodes in place. The call must also
+ * provide the number of nodes contained in the chunk so that during hydration
+ * we can know how many nodes the static vnode should adopt.
+ *
+ * The optimization scans a children list that contains hoisted nodes, and
+ * tries to find the largest chunk of consecutive hoisted nodes before running
+ * into a non-hoisted node or the end of the list. A chunk is then converted
+ * into a single static vnode and replaces the hoisted expression of the first
+ * node in the chunk. Other nodes in the chunk are considered "merged" and
+ * therefore removed from both the hoist list and the children array.
+ *
+ * This optimization is only performed in Node.js.
+ */
export const stringifyStatic: HoistTransform = (children, context) => {
let nc = 0 // current node count
let ec = 0 // current element with binding count