瀏覽代碼

refactor(runtime-vapor): simplify DynamicFragment hydrate treeshaking (#14321)

edison 3 月之前
父節點
當前提交
69d3a07087
共有 2 個文件被更改,包括 61 次插入81 次删除
  1. 2 79
      packages/runtime-vapor/src/dom/hydration.ts
  2. 59 2
      packages/runtime-vapor/src/fragment.ts

+ 2 - 79
packages/runtime-vapor/src/dom/hydration.ts

@@ -1,9 +1,4 @@
-import {
-  MismatchTypes,
-  isMismatchAllowed,
-  queuePostFlushCb,
-  warn,
-} from '@vue/runtime-dom'
+import { MismatchTypes, isMismatchAllowed, warn } from '@vue/runtime-dom'
 import {
   type ChildItem,
   insertionAnchor,
@@ -14,7 +9,6 @@ import {
 import {
   _child,
   _next,
-  createComment,
   createElement,
   createTextNode,
   disableHydrationNodeLookup,
@@ -22,15 +16,10 @@ import {
   locateChildByLogicalIndex,
   parentNode,
 } from './node'
-import { findBlockNode, remove } from '../block'
-import type { DynamicFragment } from '../fragment'
+import { remove } from '../block'
 
 export let currentHydrationNode: Node | null = null
 
-let _hydrateDynamicFragment:
-  | ((frag: DynamicFragment, isEmpty: boolean) => void)
-  | undefined
-
 export let isHydrating = false
 function setIsHydrating(value: boolean) {
   try {
@@ -59,7 +48,6 @@ function performHydration<T>(
   if (!isOptimized) {
     adoptTemplate = adoptTemplateImpl
     locateHydrationNode = locateHydrationNodeImpl
-    _hydrateDynamicFragment = hydrateDynamicFragmentImpl
     // optimize anchor cache lookup
     ;(Comment.prototype as any).$fe = undefined
     ;(Node.prototype as any).$pns = undefined
@@ -317,68 +305,3 @@ export function removeFragmentNodes(node: Node, endAnchor?: Node): void {
     }
   }
 }
-
-export function hydrateDynamicFragment(
-  frag: DynamicFragment,
-  isEmpty: boolean,
-): void {
-  _hydrateDynamicFragment && _hydrateDynamicFragment(frag, isEmpty)
-}
-
-// Hydrate implementation for DynamicFragment
-function hydrateDynamicFragmentImpl(
-  frag: DynamicFragment,
-  isEmpty: boolean,
-): void {
-  // avoid repeated hydration during fallback rendering
-  if (frag.anchor) return
-
-  if (frag.anchorLabel === 'if') {
-    // reuse the empty comment node as the anchor for empty if
-    // e.g. `<div v-if="false"></div>` -> `<!---->`
-    if (isEmpty) {
-      frag.anchor = locateFragmentEndAnchor('')!
-      if (__DEV__ && !frag.anchor) {
-        throw new Error(
-          'Failed to locate if anchor. this is likely a Vue internal bug.',
-        )
-      } else {
-        if (__DEV__) {
-          ;(frag.anchor as Comment).data = frag.anchorLabel
-        }
-        return
-      }
-    }
-  } else if (frag.anchorLabel === 'slot') {
-    // reuse the empty comment node for empty slot
-    // e.g. `<slot v-if="false"></slot>`
-    if (isEmpty && isComment(currentHydrationNode!, '')) {
-      frag.anchor = currentHydrationNode!
-      if (__DEV__) {
-        ;(frag.anchor as Comment).data = frag.anchorLabel!
-      }
-      return
-    }
-
-    // reuse the vdom fragment end anchor
-    frag.anchor = locateFragmentEndAnchor()!
-    if (__DEV__ && !frag.anchor) {
-      throw new Error(
-        'Failed to locate slot anchor. this is likely a Vue internal bug.',
-      )
-    } else {
-      return
-    }
-  }
-
-  const { parentNode: pn, nextNode } = findBlockNode(frag.nodes)!
-  // create an anchor
-  queuePostFlushCb(() => {
-    pn!.insertBefore(
-      (frag.anchor = __DEV__
-        ? createComment(frag.anchorLabel!)
-        : createTextNode()),
-      nextNode,
-    )
-  })
-}

+ 59 - 2
packages/runtime-vapor/src/fragment.ts

@@ -7,6 +7,7 @@ import {
   type VaporTransitionHooks,
   applyTransitionHooks,
   applyTransitionLeaveHooks,
+  findBlockNode,
   insert,
   isValidBlock,
   remove,
@@ -16,6 +17,7 @@ import {
   type TransitionHooks,
   type VNode,
   currentInstance,
+  queuePostFlushCb,
   setCurrentInstance,
   warnExtraneousAttributes,
 } from '@vue/runtime-dom'
@@ -26,8 +28,10 @@ import {
 } from './component'
 import type { NodeRef } from './apiTemplateRef'
 import {
-  hydrateDynamicFragment,
+  currentHydrationNode,
+  isComment,
   isHydrating,
+  locateFragmentEndAnchor,
   locateHydrationNode,
 } from './dom/hydration'
 import { isArray } from '@vue/shared'
@@ -290,7 +294,60 @@ export class DynamicFragment extends VaporFragment {
   }
 
   hydrate = (isEmpty = false): void => {
-    hydrateDynamicFragment(this, isEmpty)
+    // early return allows tree-shaking of hydration logic when not used
+    if (!isHydrating) return
+
+    // avoid repeated hydration during fallback rendering
+    if (this.anchor) return
+
+    if (this.anchorLabel === 'if') {
+      // reuse the empty comment node as the anchor for empty if
+      // e.g. `<div v-if="false"></div>` -> `<!---->`
+      if (isEmpty) {
+        this.anchor = locateFragmentEndAnchor('')!
+        if (__DEV__ && !this.anchor) {
+          throw new Error(
+            'Failed to locate if anchor. this is likely a Vue internal bug.',
+          )
+        } else {
+          if (__DEV__) {
+            ;(this.anchor as Comment).data = this.anchorLabel
+          }
+          return
+        }
+      }
+    } else if (this.anchorLabel === 'slot') {
+      // reuse the empty comment node for empty slot
+      // e.g. `<slot v-if="false"></slot>`
+      if (isEmpty && isComment(currentHydrationNode!, '')) {
+        this.anchor = currentHydrationNode!
+        if (__DEV__) {
+          ;(this.anchor as Comment).data = this.anchorLabel!
+        }
+        return
+      }
+
+      // reuse the vdom fragment end anchor
+      this.anchor = locateFragmentEndAnchor()!
+      if (__DEV__ && !this.anchor) {
+        throw new Error(
+          'Failed to locate slot anchor. this is likely a Vue internal bug.',
+        )
+      } else {
+        return
+      }
+    }
+
+    const { parentNode: pn, nextNode } = findBlockNode(this.nodes)!
+    // create an anchor
+    queuePostFlushCb(() => {
+      pn!.insertBefore(
+        (this.anchor = __DEV__
+          ? createComment(this.anchorLabel!)
+          : createTextNode()),
+        nextNode,
+      )
+    })
   }
 }