Bladeren bron

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.
Evan You 6 jaren geleden
bovenliggende
commit
d965bb6227

+ 4 - 1
packages/compiler-core/src/transforms/hoistStatic.ts

@@ -43,6 +43,7 @@ function walk(
   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.
@@ -55,6 +56,7 @@ function walk(
         ;(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
@@ -81,6 +83,7 @@ function walk(
       isStaticNode(child.content, resultCache)
     ) {
       child.codegenNode = context.hoist(child.codegenNode)
+      hasHoistedNode = true
     }
 
     // walk further
@@ -98,7 +101,7 @@ function walk(
     }
   }
 
-  if (context.transformHoist) {
+  if (hasHoistedNode && context.transformHoist) {
     context.transformHoist(children, context)
   }
 }

+ 23 - 3
packages/compiler-dom/src/transforms/stringifyStatic.ts

@@ -35,9 +35,29 @@ export const enum StringifyThresholds {
 
 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