浏览代码

wip: save

daiwei 1 月之前
父节点
当前提交
b0a42008f9

+ 21 - 1
packages/runtime-vapor/src/apiCreateDynamicComponent.ts

@@ -1,5 +1,6 @@
 import {
   type ComponentInternalInstance,
+  Fragment,
   currentInstance,
   isKeepAlive,
   isVNode,
@@ -21,7 +22,13 @@ import {
   isLastInsertion,
   resetInsertionState,
 } from './insertionState'
-import { advanceHydrationNode, isHydrating } from './dom/hydration'
+import {
+  advanceHydrationNode,
+  currentHydrationNode,
+  isComment,
+  isHydrating,
+  setCurrentHydrationNode,
+} from './dom/hydration'
 import { DynamicFragment, type VaporFragment } from './fragment'
 import type { KeepAliveInstance } from './components/KeepAlive'
 import { isInteropEnabled } from './vdomInteropState'
@@ -63,6 +70,19 @@ export function createDynamicComponent(
 
         const frag = appContext.vapor.vdomMountVNode(value, currentInstance)
         if (isHydrating) {
+          // Consume the outer <!--[--> anchor so VDOM hydration
+          // starts at the actual first DOM node. For Fragment VNodes
+          // (whose SSR also starts with <!--[-->), only skip when
+          // nested anchors are detected (nextSibling is also <!--[-->).
+          if (
+            !isSingleRoot &&
+            isComment(currentHydrationNode!, '[') &&
+            !currentHydrationNode!.previousSibling &&
+            (value.type !== Fragment ||
+              isComment(currentHydrationNode!.nextSibling!, '['))
+          ) {
+            setCurrentHydrationNode(currentHydrationNode!.nextSibling!)
+          }
           frag.hydrate()
           if (_isLastInsertion) {
             advanceHydrationNode(_insertionParent!)

+ 11 - 0
packages/runtime-vapor/src/component.ts

@@ -94,6 +94,7 @@ import {
   advanceHydrationNode,
   currentHydrationNode,
   currentHydrationStartNode,
+  isComment,
   isHydrating,
   locateHydrationNode,
   locateNextNode,
@@ -308,6 +309,16 @@ export function createComponent(
     if (!isHydrating) {
       if (_insertionParent) insert(frag, _insertionParent, _insertionAnchor)
     } else {
+      // For multi-root VDOM components, consume the outer <!--[-->
+      // anchor so VDOM hydration starts at the actual first DOM node.
+      if (
+        !isSingleRoot &&
+        isComment(currentHydrationNode!, '[') &&
+        (!currentHydrationNode!.previousSibling ||
+          currentHydrationNode === currentHydrationStartNode)
+      ) {
+        setCurrentHydrationNode(currentHydrationNode!.nextSibling!)
+      }
       frag.hydrate()
       if (_isLastInsertion) {
         advanceHydrationNode(_insertionParent!)

+ 0 - 35
packages/runtime-vapor/src/vdomInterop.ts

@@ -80,7 +80,6 @@ import { optimizePropertyLookup } from './dom/prop'
 import {
   advanceHydrationNode,
   currentHydrationNode,
-  currentHydrationStartNode,
   isComment,
   isHydrating,
   setCurrentHydrationNode,
@@ -483,20 +482,6 @@ function mountVNode(
 
   frag.hydrate = () => {
     if (!isHydrating) return
-    // The hydration cursor may be sitting on a fragment start anchor
-    // (`<!--[-->`) from the parent's multi-root wrapper or VDOM slot.
-    // Skip it so runtime-core hydrateNode() receives the actual first
-    // DOM node. For Fragment VNodes (whose own SSR output also starts
-    // with `<!--[-->`), only skip when the next sibling is also
-    // `<!--[-->`, confirming nested anchors (outer = parent's, inner =
-    // Fragment's own).
-    if (
-      isOuterFragmentAnchor() &&
-      (vnode.type !== Fragment ||
-        isComment(currentHydrationNode!.nextSibling!, '['))
-    ) {
-      setCurrentHydrationNode(currentHydrationNode!.nextSibling!)
-    }
     hydrateVNode(vnode, parentComponent as any)
     onScopeDispose(unmount, true)
     isMounted = true
@@ -650,11 +635,6 @@ function createVDOMComponent(
 
   frag.hydrate = () => {
     if (!isHydrating) return
-    // For multi-root components, skip the VDOM fragment start anchor
-    // so that VDOM hydration receives this component's actual first DOM node
-    if (!isSingleRoot && isOuterFragmentAnchor()) {
-      setCurrentHydrationNode(currentHydrationNode!.nextSibling!)
-    }
     hydrateVNode(vnode, parentComponent as any)
     onScopeDispose(unmount, true)
     isMounted = true
@@ -968,21 +948,6 @@ export const vaporInteropPlugin: Plugin = app => {
   }) satisfies App['mount']
 }
 
-/**
- * Check if the current hydration node is a VDOM fragment start anchor
- * (`<!--[-->`) belonging to the parent rather than the VDOM component
- * itself
- */
-function isOuterFragmentAnchor(): boolean {
-  return (
-    isComment(currentHydrationNode!, '[') &&
-    // first child of parent
-    (!currentHydrationNode!.previousSibling ||
-      // matches the parent component's hydration start node
-      currentHydrationNode === currentHydrationStartNode)
-  )
-}
-
 function hydrateVNode(
   vnode: VNode,
   parentComponent: ComponentInternalInstance | null,