import { PatchFlags, SlotFlags } from '@vue/shared'
import { warn } from '../warning'
-export let shouldTrackInSlotRendering = 0
+export let isRenderingCompiledSlot = 0
/**
* Compiler runtime helper for rendering `<slot/>`
// invocation interfering with template-based block tracking, but in
// `renderSlot` we can be sure that it's template-based so we can force
// enable it.
- shouldTrackInSlotRendering++
+ isRenderingCompiledSlot++
const rendered = (openBlock(),
createBlock(
Fragment,
? PatchFlags.STABLE_FRAGMENT
: PatchFlags.BAIL
))
- shouldTrackInSlotRendering--
+ isRenderingCompiledSlot--
return rendered
}
currentRenderingInstance
} from '../componentRenderUtils'
import { ComponentInternalInstance } from '../component'
-import { setBlockTracking } from '../vnode'
+import { isRenderingCompiledSlot } from './renderSlot'
+import { closeBlock, openBlock } from '../vnode'
/**
* Wrap a slot function to memoize current rendering instance
) {
if (!ctx) return fn
return function renderFnWithContext() {
- // By default, compiled slots disables block tracking since the user may
- // call it inside a template expression (#1745). It should only track when
- // it's called by a template `<slot>`.
- setBlockTracking(-1)
+ // If a user calls a compiled slot inside a template expression (#1745), it
+ // can mess up block tracking, so by default we need to push a null block to
+ // avoid that. This isn't necessary if rendering a compiled `<slot>`.
+ if (!isRenderingCompiledSlot) {
+ openBlock(true /* null block that disables tracking */)
+ }
const owner = currentRenderingInstance
setCurrentRenderingInstance(ctx)
const res = fn.apply(null, arguments as any)
setCurrentRenderingInstance(owner)
- setBlockTracking(1)
+ if (!isRenderingCompiledSlot) {
+ closeBlock()
+ }
return res
}
}
import { RendererNode, RendererElement } from './renderer'
import { NULL_DYNAMIC_COMPONENT } from './helpers/resolveAssets'
import { hmrDirtyComponents } from './hmr'
-import { shouldTrackInSlotRendering } from './helpers/renderSlot'
export const Fragment = (Symbol(__DEV__ ? 'Fragment' : undefined) as any) as {
__isFragment: true
// can divide a template into nested blocks, and within each block the node
// structure would be stable. This allows us to skip most children diffing
// and only worry about the dynamic nodes (indicated by patch flags).
-const blockStack: (VNode[] | null)[] = []
+export const blockStack: (VNode[] | null)[] = []
let currentBlock: VNode[] | null = null
/**
blockStack.push((currentBlock = disableTracking ? null : []))
}
+export function closeBlock() {
+ blockStack.pop()
+ currentBlock = blockStack[blockStack.length - 1] || null
+}
+
// Whether we should be tracking dynamic child nodes inside a block.
// Only tracks when this value is > 0
// We are not using a simple boolean because this value may need to be
// save current block children on the block vnode
vnode.dynamicChildren = currentBlock || EMPTY_ARR
// close block
- blockStack.pop()
- currentBlock = blockStack[blockStack.length - 1] || null
+ closeBlock()
// a block is always going to be patched, so track it as a child of its
// parent block
if (currentBlock) {
normalizeChildren(vnode, children)
if (
- (shouldTrack > 0 || shouldTrackInSlotRendering > 0) &&
+ shouldTrack > 0 &&
// avoid a block node from tracking itself
!isBlockNode &&
// has current parent block