diff --git a/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts b/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
index c2073b966a7..2dbe87e6c43 100644
--- a/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
+++ b/packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts
@@ -23,7 +23,9 @@ import {
createApp,
FunctionalComponent,
renderList,
- onUnmounted
+ onUnmounted,
+ createElementBlock,
+ createElementVNode
} from '@vue/runtime-test'
import { PatchFlags, SlotFlags } from '@vue/shared'
import { SuspenseImpl } from '../src/components/Suspense'
@@ -697,6 +699,81 @@ describe('renderer: optimized mode', () => {
)
})
+ test('force full diff slot and fallback nodes', async () => {
+ const Comp = {
+ props: ['show'],
+ setup(props: any, { slots }: SetupContext) {
+ return () => {
+ return (
+ openBlock(),
+ createElementBlock('div', null, [
+ renderSlot(slots, 'default', { hide: !props.show }, () => [
+ true
+ ? (openBlock(),
+ (block = createElementBlock(
+ Fragment,
+ { key: 0 },
+ [createTextVNode('foo')],
+ PatchFlags.STABLE_FRAGMENT
+ )))
+ : createCommentVNode('v-if', true)
+ ])
+ ])
+ )
+ }
+ }
+ }
+
+ const show = ref(true)
+ const app = createApp({
+ render() {
+ return (
+ openBlock(),
+ createBlock(
+ Comp,
+ { show: show.value },
+ {
+ default: withCtx(({ hide }: { hide: boolean }) => [
+ !hide
+ ? (openBlock(),
+ createElementBlock(
+ Fragment,
+ { key: 0 },
+ [
+ createCommentVNode('comment'),
+ createElementVNode(
+ 'div',
+ null,
+ 'bar',
+ PatchFlags.HOISTED
+ )
+ ],
+ PatchFlags.STABLE_FRAGMENT
+ ))
+ : createCommentVNode('v-if', true)
+ ]),
+ _: SlotFlags.STABLE
+ },
+ PatchFlags.PROPS,
+ ['show']
+ )
+ )
+ }
+ })
+
+ app.mount(root)
+ expect(inner(root)).toBe('
')
+ expect(block).toBe(null)
+
+ show.value = false
+ await nextTick()
+ expect(inner(root)).toBe('foo
')
+
+ show.value = true
+ await nextTick()
+ expect(inner(root)).toBe('')
+ })
+
// 3569
test('should force bailout when the user manually calls the slot function', async () => {
const index = ref(0)
diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts
index 452fc827269..f5d8ca4041e 100644
--- a/packages/runtime-core/src/helpers/renderSlot.ts
+++ b/packages/runtime-core/src/helpers/renderSlot.ts
@@ -38,7 +38,14 @@ export function renderSlot(
currentRenderingInstance!.parent.isCE)
) {
if (name !== 'default') props.name = name
- return createVNode('slot', props, fallback && fallback())
+ let renderFallback = false
+ const node = createVNode(
+ 'slot',
+ props,
+ fallback && ((renderFallback = true), fallback())
+ )
+ if (renderFallback) node.patchFlag = PatchFlags.BAIL
+ return node
}
let slot = slots[name]
@@ -59,6 +66,7 @@ export function renderSlot(
if (slot && (slot as ContextualRenderFn)._c) {
;(slot as ContextualRenderFn)._d = false
}
+ let renderFallback = false
openBlock()
const validSlotContent = slot && ensureValidVNode(slot(props))
const rendered = createBlock(
@@ -71,7 +79,7 @@ export function renderSlot(
(validSlotContent && (validSlotContent as any).key) ||
`_${name}`
},
- validSlotContent || (fallback ? fallback() : []),
+ validSlotContent || (fallback ? ((renderFallback = true), fallback()) : []),
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
? PatchFlags.STABLE_FRAGMENT
: PatchFlags.BAIL
@@ -82,6 +90,7 @@ export function renderSlot(
if (slot && (slot as ContextualRenderFn)._c) {
;(slot as ContextualRenderFn)._d = true
}
+ if (renderFallback) rendered.patchFlag = PatchFlags.BAIL
return rendered
}
diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts
index 383e17fb0f5..7ed3f1f7a74 100644
--- a/packages/runtime-core/src/renderer.ts
+++ b/packages/runtime-core/src/renderer.ts
@@ -825,7 +825,7 @@ function baseCreateRenderer(
}
const areChildrenSVG = isSVG && n2.type !== 'foreignObject'
- if (dynamicChildren) {
+ if (optimized && dynamicChildren) {
patchBlockChildren(
n1.dynamicChildren!,
dynamicChildren,
@@ -1058,9 +1058,10 @@ function baseCreateRenderer(
let { patchFlag, dynamicChildren, slotScopeIds: fragmentSlotScopeIds } = n2
if (
- __DEV__ &&
- // #5523 dev root fragment may inherit directives
- (isHmrUpdating || patchFlag & PatchFlags.DEV_ROOT_FRAGMENT)
+ (__DEV__ &&
+ // #5523 dev root fragment may inherit directives
+ (isHmrUpdating || patchFlag & PatchFlags.DEV_ROOT_FRAGMENT)) ||
+ (n1 || n2).patchFlag === PatchFlags.BAIL
) {
// HMR updated / Dev root fragment (w/ comments), force full diff
patchFlag = 0
@@ -1093,6 +1094,7 @@ function baseCreateRenderer(
)
} else {
if (
+ optimized &&
patchFlag > 0 &&
patchFlag & PatchFlags.STABLE_FRAGMENT &&
dynamicChildren &&