Bladeren bron

chore: update

daiwei 5 maanden geleden
bovenliggende
commit
3e8e12ca27

+ 3 - 6
packages/runtime-vapor/src/block.ts

@@ -255,20 +255,17 @@ export function setScopeId(block: Block, scopeIds: string[]): void {
 }
 
 export function setComponentScopeId(instance: VaporComponentInstance): void {
-  const { parent, slotOwner } = instance
-  if (!parent && !slotOwner) return
+  const { parent, slotOwnerScopeId } = instance
+  if (!parent) return
   // prevent setting scopeId on multi-root fragments
   if (isArray(instance.block) && instance.block.length > 1) return
 
   const scopeIds: string[] = []
-
-  const scopeOwner = slotOwner || parent
-  const scopeId = scopeOwner && scopeOwner.type.__scopeId
+  const scopeId = slotOwnerScopeId || (parent && parent.type.__scopeId)
   if (scopeId) scopeIds.push(scopeId)
 
   // inherit scopeId from vdom parent
   if (
-    parent &&
     parent.subTree &&
     (parent.subTree.component as any) === instance &&
     parent.vnode!.scopeId

+ 8 - 8
packages/runtime-vapor/src/component.ts

@@ -69,10 +69,10 @@ import {
   type RawSlots,
   type StaticSlots,
   type VaporSlot,
+  currentSlotConsumer,
+  currentSlotOwner,
   dynamicSlotsProxyHandlers,
   getSlot,
-  getSlotConsumer,
-  getSlotOwner,
 } from './componentSlots'
 import { hmrReload, hmrRerender } from './hmr'
 import {
@@ -193,8 +193,9 @@ export function createComponent(
     resetInsertionState()
   }
 
-  const parentInstance =
-    getSlotConsumer() || (currentInstance as VaporComponentInstance | null)
+  // when rendering components in slot, currentInstance is changed in withVaporCtx
+  // should use currentSlotConsumer as parent
+  const parentInstance = currentSlotConsumer || currentInstance
 
   if (
     isSingleRoot &&
@@ -477,8 +478,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
 
   slots: StaticSlots
 
-  // slot owner for scopeId inheritance
-  slotOwner?: VaporComponentInstance | null
+  slotOwnerScopeId?: string | null
 
   // to hold vnode props / slots in vdom interop mode
   rawPropsRef?: ShallowRef<any>
@@ -606,7 +606,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
         : rawSlots
       : EMPTY_OBJ
 
-    this.slotOwner = getSlotOwner()
+    this.slotOwnerScopeId = currentSlotOwner && currentSlotOwner.type.__scopeId
 
     // apply custom element special handling
     if (comp.ce) {
@@ -680,7 +680,7 @@ export function createPlainElement(
   ;(el as any).$root = isSingleRoot
 
   if (!isHydrating) {
-    const scopeOwner = getSlotOwner() || currentInstance
+    const scopeOwner = currentSlotOwner || currentInstance
     const scopeId = scopeOwner && scopeOwner.type.__scopeId
     if (scopeId) setScopeId(el, [scopeId])
   }

+ 39 - 30
packages/runtime-vapor/src/componentSlots.ts

@@ -122,34 +122,41 @@ export function getSlot(
   }
 }
 
-// Tracks slot execution context: the owner that defined the slot, and the
-// consumer that is currently rendering it.
-const slotOwnerStack: (VaporComponentInstance | null)[] = []
-const slotConsumerStack: (VaporComponentInstance | null)[] = []
+export let currentSlotOwner: GenericComponentInstance | null = null
+export let currentSlotConsumer: GenericComponentInstance | null = null
 
-export function getSlotOwner(): VaporComponentInstance | null {
-  return slotOwnerStack.length > 0
-    ? slotOwnerStack[slotOwnerStack.length - 1]
-    : null
+function setCurrentSlotOwner(owner: GenericComponentInstance | null) {
+  try {
+    return currentSlotOwner
+  } finally {
+    currentSlotOwner = owner
+  }
 }
 
-export function getSlotConsumer(): VaporComponentInstance | null {
-  return slotConsumerStack.length > 0
-    ? slotConsumerStack[slotConsumerStack.length - 1]
-    : null
+function setCurrentSlotConsumer(consumer: GenericComponentInstance | null) {
+  try {
+    return currentSlotConsumer
+  } finally {
+    currentSlotConsumer = consumer
+  }
 }
 
+/**
+ * Wrap a slot function to memoize currentInstance
+ * 1. ensure correct currentInstance in forwarded slots
+ * 2. elements created in the slot inherit the slot owner's scopeId
+ */
 export function withVaporCtx(fn: Function): BlockFn {
-  const ownerInstance = currentInstance as VaporComponentInstance | null
+  const owner = currentInstance
   return (...args: any[]) => {
-    const prev = setCurrentInstance(ownerInstance)
-    slotOwnerStack.push(ownerInstance)
-    slotConsumerStack.push(prev[0] as VaporComponentInstance | null)
+    const prev = setCurrentInstance(owner)
+    const prevOwner = setCurrentSlotOwner(owner)
+    const prevConsumer = setCurrentSlotConsumer(prev[0])
     try {
       return fn(...args)
     } finally {
-      slotConsumerStack.pop()
-      slotOwnerStack.pop()
+      setCurrentSlotConsumer(prevConsumer)
+      setCurrentSlotOwner(prevOwner)
       setCurrentInstance(...prev)
     }
   }
@@ -166,9 +173,8 @@ export function createSlot(
   const _isLastInsertion = isLastInsertion
   if (!isHydrating) resetInsertionState()
 
-  const consumer = currentInstance as VaporComponentInstance
-  const owner = getSlotOwner() || consumer
-  const rawSlots = consumer!.rawSlots
+  const instance = currentInstance as VaporComponentInstance
+  const rawSlots = instance.rawSlots
   const slotProps = rawProps
     ? new Proxy(rawProps, rawPropsProxyHandlers)
     : EMPTY_OBJ
@@ -176,11 +182,11 @@ export function createSlot(
   let fragment: DynamicFragment
   if (isRef(rawSlots._)) {
     if (isHydrating) locateHydrationNode()
-    fragment = owner.appContext.vapor!.vdomSlot(
+    fragment = instance.appContext.vapor!.vdomSlot(
       rawSlots._,
       name,
       slotProps,
-      owner,
+      instance,
       fallback,
     )
   } else {
@@ -190,9 +196,10 @@ export function createSlot(
         : new DynamicFragment()
     const isDynamicName = isFunction(name)
 
+    // Calculate slotScopeIds once (for vdom interop)
     const slotScopeIds: string[] = []
     if (!noSlotted) {
-      const scopeId = owner.type.__scopeId
+      const scopeId = instance.type.__scopeId
       if (scopeId) {
         slotScopeIds.push(`${scopeId}-s`)
       }
@@ -201,11 +208,14 @@ export function createSlot(
     const renderSlot = () => {
       const slotName = isFunction(name) ? name() : name
 
+      // in custom element mode, render <slot/> as actual slot outlets
+      // because in shadowRoot: false mode the slot element gets
+      // replaced by injected content
       if (
-        (consumer as GenericComponentInstance).ce ||
-        (consumer.parent &&
-          isAsyncWrapper(consumer.parent) &&
-          consumer.parent.ce)
+        (instance as GenericComponentInstance).ce ||
+        (instance.parent &&
+          isAsyncWrapper(instance.parent) &&
+          instance.parent.ce)
       ) {
         const el = createElement('slot')
         renderEffect(() => {
@@ -224,7 +234,6 @@ export function createSlot(
         fragment.fallback = fallback
         // Create and cache bound version of the slot to make it stable
         // so that we avoid unnecessary updates if it resolves to the same slot
-
         fragment.update(
           slot._bound ||
             (slot._bound = () => {
@@ -253,7 +262,7 @@ export function createSlot(
 
   if (!isHydrating) {
     if (!noSlotted) {
-      const scopeId = owner.type.__scopeId
+      const scopeId = instance.type.__scopeId
       if (scopeId) {
         setScopeId(fragment, [`${scopeId}-s`])
       }

+ 9 - 7
packages/runtime-vapor/src/vdomInterop.ts

@@ -59,7 +59,11 @@ import {
 } from '@vue/shared'
 import { type RawProps, rawPropsProxyHandlers } from './componentProps'
 import type { RawSlots, VaporSlot } from './componentSlots'
-import { currentSlotScopeIds, getSlotOwner } from './componentSlots'
+import {
+  currentSlotConsumer,
+  currentSlotOwner,
+  currentSlotScopeIds,
+} from './componentSlots'
 import { renderEffect } from './renderEffect'
 import { _next, createTextNode } from './dom/node'
 import { optimizePropertyLookup } from './dom/prop'
@@ -276,7 +280,8 @@ function createVDOMComponent(
   rawProps?: LooseRawProps | null,
   rawSlots?: LooseRawSlots | null,
 ): VaporFragment {
-  const parentInstance = currentInstance as VaporComponentInstance
+  const parentInstance = (currentSlotConsumer ||
+    currentInstance) as VaporComponentInstance
   const frag = new VaporFragment([])
   const vnode = (frag.vnode = createVNode(
     component,
@@ -335,11 +340,8 @@ function createVDOMComponent(
     frag.nodes = vnode.el as any
   }
 
-  const scopeOwner =
-    getSlotOwner() ||
-    (parentInstance && parentInstance.slotOwner) ||
-    parentInstance
-  vnode.scopeId = scopeOwner && scopeOwner.type.__scopeId!
+  const scopeOwner = currentSlotOwner || parentInstance
+  vnode.scopeId = (scopeOwner && scopeOwner.type.__scopeId) || null
   vnode.slotScopeIds = currentSlotScopeIds
 
   frag.insert = (parentNode, anchor, transition) => {