Răsfoiți Sursa

Merge branch 'minor' into rolldown

edison 3 luni în urmă
părinte
comite
fd58a1bb82

+ 40 - 0
packages/runtime-vapor/__tests__/componentSlots.spec.ts

@@ -527,6 +527,46 @@ describe('component: slots', () => {
       expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
     })
 
+    test('slots proxy ownKeys trap correctly reflects dynamic slot presence', async () => {
+      const val = ref('header')
+      const toggle = ref(false)
+
+      let instance: any
+      const Comp = defineVaporComponent(() => {
+        instance = currentInstance
+        const n0 = template('<div></div>')()
+        prepend(n0 as any as ParentNode, createSlot('header', null))
+        return n0
+      })
+
+      define(() => {
+        // dynamic slot
+        return createComponent(Comp, null, {
+          $: [
+            () =>
+              (toggle.value
+                ? {
+                    name: val.value,
+                    fn: () => {
+                      return template('<h1></h1>')()
+                    },
+                  }
+                : void 0) as DynamicSlot,
+          ],
+        })
+      }).render()
+
+      expect(Reflect.ownKeys(instance.slots)).not.toContain('header')
+
+      toggle.value = true
+      await nextTick()
+      expect(Reflect.ownKeys(instance.slots)).toContain('header')
+
+      toggle.value = false
+      await nextTick()
+      expect(Reflect.ownKeys(instance.slots)).not.toContain('header')
+    })
+
     test('render fallback when slot content is not valid', async () => {
       const Child = {
         setup() {

+ 6 - 4
packages/runtime-vapor/src/componentSlots.ts

@@ -75,10 +75,12 @@ export const dynamicSlotsProxyHandlers: ProxyHandler<RawSlots> = {
       for (const source of dynamicSources) {
         if (isFunction(source)) {
           const slot = resolveFunctionSource(source)
-          if (isArray(slot)) {
-            for (const s of slot) keys.push(String(s.name))
-          } else {
-            keys.push(String(slot.name))
+          if (slot) {
+            if (isArray(slot)) {
+              for (const s of slot) keys.push(String(s.name))
+            } else {
+              keys.push(String(slot.name))
+            }
           }
         } else {
           keys.push(...Object.keys(source))

+ 11 - 13
packages/runtime-vapor/src/dom/hydration.ts

@@ -25,29 +25,27 @@ import {
 import { findBlockNode, remove } from '../block'
 import type { DynamicFragment } from '../fragment'
 
-const isHydratingStack = [] as boolean[]
-export let isHydrating = false
 export let currentHydrationNode: Node | null = null
 
 let _hydrateDynamicFragment:
   | ((frag: DynamicFragment, isEmpty: boolean) => void)
   | undefined
 
-function pushIsHydrating(value: boolean): void {
-  isHydratingStack.push((isHydrating = value))
-}
-
-function popIsHydrating(): void {
-  isHydratingStack.pop()
-  isHydrating = isHydratingStack[isHydratingStack.length - 1] || false
+export let isHydrating = false
+function setIsHydrating(value: boolean) {
+  try {
+    return isHydrating
+  } finally {
+    isHydrating = value
+  }
 }
 
 export function runWithoutHydration(fn: () => any): any {
+  const prev = setIsHydrating(false)
   try {
-    pushIsHydrating(false)
     return fn()
   } finally {
-    popIsHydrating()
+    setIsHydrating(prev)
   }
 }
 
@@ -75,12 +73,12 @@ function performHydration<T>(
     isOptimized = true
   }
   enableHydrationNodeLookup()
-  pushIsHydrating(true)
+  const prev = setIsHydrating(true)
   setup()
   const res = fn()
   cleanup()
   currentHydrationNode = null
-  popIsHydrating()
+  setIsHydrating(prev)
   if (!isHydrating) disableHydrationNodeLookup()
   return res
 }