feat: improve static content stringiciation

Now a single static vnode can contain stringified content
for multiple consecutive nodes, which greatly improves the
coverage of this optimization.
This commit is contained in:
Evan You 2020-05-16 21:30:16 -04:00
parent 59d50dad9c
commit d965bb6227
2 changed files with 27 additions and 4 deletions

View File

@ -43,6 +43,7 @@ function walk(
resultCache: Map<TemplateChildNode, boolean>, resultCache: Map<TemplateChildNode, boolean>,
doNotHoistNode: boolean = false doNotHoistNode: boolean = false
) { ) {
let hasHoistedNode = false
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
const child = children[i] const child = children[i]
// only plain elements & text calls are eligible for hoisting. // only plain elements & text calls are eligible for hoisting.
@ -55,6 +56,7 @@ function walk(
;(child.codegenNode as VNodeCall).patchFlag = ;(child.codegenNode as VNodeCall).patchFlag =
PatchFlags.HOISTED + (__DEV__ ? ` /* HOISTED */` : ``) PatchFlags.HOISTED + (__DEV__ ? ` /* HOISTED */` : ``)
child.codegenNode = context.hoist(child.codegenNode!) child.codegenNode = context.hoist(child.codegenNode!)
hasHoistedNode = true
continue continue
} else { } else {
// node may contain dynamic children, but its props may be eligible for // node may contain dynamic children, but its props may be eligible for
@ -81,6 +83,7 @@ function walk(
isStaticNode(child.content, resultCache) isStaticNode(child.content, resultCache)
) { ) {
child.codegenNode = context.hoist(child.codegenNode) child.codegenNode = context.hoist(child.codegenNode)
hasHoistedNode = true
} }
// walk further // walk further
@ -98,7 +101,7 @@ function walk(
} }
} }
if (context.transformHoist) { if (hasHoistedNode && context.transformHoist) {
context.transformHoist(children, context) context.transformHoist(children, context)
} }
} }

View File

@ -35,9 +35,29 @@ export const enum StringifyThresholds {
type StringiableNode = PlainElementNode | TextCallNode type StringiableNode = PlainElementNode | TextCallNode
// Turn eligible hoisted static trees into stringied static nodes, e.g. /**
// const _hoisted_1 = createStaticVNode(`<div class="foo">bar</div>`) * Turn eligible hoisted static trees into stringied static nodes, e.g.
// This is only performed in non-in-browser compilations. *
* ```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) => { export const stringifyStatic: HoistTransform = (children, context) => {
let nc = 0 // current node count let nc = 0 // current node count
let ec = 0 // current element with binding count let ec = 0 // current element with binding count