]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf: cache static children on parent
authordaiwei <daiwei521@126.com>
Mon, 8 Sep 2025 09:33:01 +0000 (17:33 +0800)
committerdaiwei <daiwei521@126.com>
Mon, 8 Sep 2025 09:33:01 +0000 (17:33 +0800)
packages/runtime-vapor/__tests__/dom/template.spec.ts
packages/runtime-vapor/src/dom/hydration.ts
packages/runtime-vapor/src/dom/node.ts
packages/runtime-vapor/src/insertionState.ts

index 85de30987a55e22b52dffda3fae163b0412e6fe1..792c55242b16102d858c784ad29c1be619c08226 100644 (file)
@@ -20,8 +20,8 @@ describe('api: template', () => {
 
   test('nthChild', () => {
     const t = template('<div><span><b>nested</b></span><p></p></div>')
-    const root = t()
-    const span = nthChild(root, 0)
+    const root = t() as ParentNode
+    const span = nthChild(root, 0) as ParentNode
     const b = nthChild(span, 0)
     const p = nthChild(root, 1)
     expect(span).toBe(root.firstChild)
@@ -31,7 +31,7 @@ describe('api: template', () => {
 
   test('next', () => {
     const t = template('<div><span></span><b></b><p></p></div>')
-    const root = t()
+    const root = t() as ParentNode
     const span = child(root as ParentNode)
     const b = next(span)
 
index aab0e76e6c38a799094063add92a8f784f5988a2..1b27a2e5fd8e0dba3def1645385e415840e48725 100644 (file)
@@ -30,6 +30,7 @@ function performHydration<T>(
     // optimize anchor cache lookup
     ;(Comment.prototype as any).$fe = undefined
     ;(Node.prototype as any).$idx = undefined
+    ;(Node.prototype as any).$children = undefined
     isOptimized = true
   }
   enableHydrationNodeLookup()
index 6a99e95bac5433741730da1ac1bdf7ad2aac74f9..a43e8315c6911c5a570315ada5c24b9fb27ddce2 100644 (file)
@@ -2,8 +2,8 @@
 
 import {
   type ChildItem,
+  type InsertionParent,
   getHydrationState,
-  getTemplateChildren,
 } from '../insertionState'
 
 export function createElement(tagName: string): HTMLElement {
@@ -46,23 +46,23 @@ const __txt: typeof __child = (node: ParentNode): Node => {
 }
 
 /* @__NO_SIDE_EFFECTS__ */
-export function _child(node: ParentNode): Node {
-  const templateChildren = getTemplateChildren(node)
-  return templateChildren ? templateChildren[0] : node.firstChild!
+export function _child(node: InsertionParent): Node {
+  const children = node.$children
+  return children ? children[0] : node.firstChild!
 }
 
 /**
  * Hydration-specific version of `child`.
  */
 /* @__NO_SIDE_EFFECTS__ */
-export function __child(node: ParentNode & { $lpn?: Node }): Node {
+export function __child(node: ParentNode): Node {
   return __nthChild(node, 0)!
 }
 
 /* @__NO_SIDE_EFFECTS__ */
-export function _nthChild(node: Node, i: number): Node {
-  const templateChildren = getTemplateChildren(node as ParentNode)
-  return templateChildren ? templateChildren[i] : node.childNodes[i]
+export function _nthChild(node: InsertionParent, i: number): Node {
+  const children = node.$children
+  return children ? children[i] : node.childNodes[i]
 }
 
 /**
@@ -92,10 +92,8 @@ export function __nthChild(node: Node, i: number): Node {
 
 /* @__NO_SIDE_EFFECTS__ */
 export function _next(node: Node): Node {
-  const templateChildren = getTemplateChildren(node.parentNode!)
-  return templateChildren
-    ? templateChildren[(node as ChildItem).$idx + 1]
-    : node.nextSibling!
+  const children = (node.parentNode! as InsertionParent).$children
+  return children ? children[(node as ChildItem).$idx + 1] : node.nextSibling!
 }
 
 /**
index bcfd900a6c2aa37dd1da70772d6a6d8a017bafbb..3cd21600e50e21d0060fece5b3cb12ce41cc01d2 100644 (file)
@@ -1,18 +1,16 @@
 import { isHydrating } from './dom/hydration'
-export interface ChildItem extends ChildNode {
-  $idx: number
-}
+export type ChildItem = ChildNode & { $idx: number }
+export type InsertionParent = ParentNode & { $children?: ChildItem[] }
+
 type HydrationState = {
   logicalChildren: ChildItem[]
   prevDynamicCount: number
   insertionAnchors: Map<Node, number> | null
   appendAnchor: Node | null
 }
-export let insertionParent: ParentNode | undefined
+export let insertionParent: InsertionParent | undefined
 export let insertionAnchor: Node | 0 | undefined | null
 
-const templateChildrenCache = new WeakMap<ParentNode, ChildItem[]>()
-
 const hydrationStateCache = new WeakMap<ParentNode, HydrationState>()
 
 /**
@@ -87,22 +85,22 @@ function initializeHydrationState(
 
 function cacheTemplateChildren(
   anchor: number | Node | null | undefined,
-  parent: ParentNode,
+  parent: InsertionParent,
 ) {
   // special handling append anchor value to null
   insertionAnchor =
     typeof anchor === 'number' && anchor > 0 ? null : (anchor as Node)
 
-  if (!templateChildrenCache.has(parent)) {
+  if (!parent.$children) {
     const nodes = parent.childNodes
     const len = nodes.length
-    const children = new Array(len)
+    const children = new Array(len) as ChildItem[]
     for (let i = 0; i < len; i++) {
       const node = nodes[i] as ChildItem
       node.$idx = i
       children[i] = node
     }
-    templateChildrenCache.set(parent, children)
+    parent.$children = children
   }
 }
 
@@ -110,12 +108,6 @@ export function resetInsertionState(): void {
   insertionParent = insertionAnchor = undefined
 }
 
-export function getTemplateChildren(
-  parent: ParentNode,
-): ChildItem[] | undefined {
-  return templateChildrenCache.get(parent)
-}
-
 export function getHydrationState(
   parent: ParentNode,
 ): HydrationState | undefined {