import { isArray, isFunction, EMPTY_OBJ, ShapeFlags } from '@vue/shared'
import { warn } from './warning'
import { isKeepAlive } from './components/KeepAlive'
+import { withCtx } from './helpers/withRenderContext'
export type Slot = (...args: any[]) => VNode[]
[name: string]: unknown
// manual render fn hint to skip forced children updates
$stable?: boolean
+ // internal, for tracking slot owner instance. This is attached during
+ // normalizeChildren when the component vnode is created.
+ _ctx?: ComponentInternalInstance | null
// internal, indicates compiler generated slots = can skip normalization
_?: 1
}
? value.map(normalizeVNode)
: [normalizeVNode(value as VNodeChild)]
-const normalizeSlot = (key: string, rawSlot: Function): Slot => (
- props: any
-) => {
- if (__DEV__ && currentInstance != null) {
- warn(
- `Slot "${key}" invoked outside of the render function: ` +
- `this will not track dependencies used in the slot. ` +
- `Invoke the slot function inside the render function instead.`
- )
- }
- return normalizeSlotValue(rawSlot(props))
-}
+const normalizeSlot = (
+ key: string,
+ rawSlot: Function,
+ ctx: ComponentInternalInstance | null | undefined
+): Slot =>
+ withCtx((props: any) => {
+ if (__DEV__ && currentInstance != null) {
+ warn(
+ `Slot "${key}" invoked outside of the render function: ` +
+ `this will not track dependencies used in the slot. ` +
+ `Invoke the slot function inside the render function instead.`
+ )
+ }
+ return normalizeSlotValue(rawSlot(props))
+ }, ctx)
export function resolveSlots(
instance: ComponentInternalInstance,
slots = children as Slots
} else {
slots = {}
+ const ctx = rawSlots._ctx
for (const key in rawSlots) {
- if (key === '$stable') continue
+ if (key === '$stable' || key === '_ctx') continue
const value = rawSlots[key]
if (isFunction(value)) {
- slots[key] = normalizeSlot(key, value)
+ slots[key] = normalizeSlot(key, value, ctx)
} else if (value != null) {
if (__DEV__) {
warn(
import { warn } from './warning'
import { currentScopeId } from './helpers/scopeId'
import { PortalImpl, isPortal } from './components/Portal'
+import { currentRenderingInstance } from './componentRenderUtils'
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
__isFragment: true
type = ShapeFlags.ARRAY_CHILDREN
} else if (typeof children === 'object') {
type = ShapeFlags.SLOTS_CHILDREN
+ if (!(children as RawSlots)._) {
+ ;(children as RawSlots)._ctx = currentRenderingInstance
+ }
} else if (isFunction(children)) {
- children = { default: children }
+ children = { default: children, _ctx: currentRenderingInstance }
type = ShapeFlags.SLOTS_CHILDREN
} else {
children = String(children)