From 53564e01b7870bcddcbd35ab439b97593d21c255 Mon Sep 17 00:00:00 2001 From: daiwei Date: Wed, 2 Apr 2025 16:30:55 +0800 Subject: [PATCH] fix(runtime-vapor): use slot fallback on initial render --- .../__tests__/componentSlots.spec.ts | 37 +++++++++++++++++++ packages/runtime-vapor/src/componentSlots.ts | 16 +++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/packages/runtime-vapor/__tests__/componentSlots.spec.ts b/packages/runtime-vapor/__tests__/componentSlots.spec.ts index 58076fff9ee..b577a18c58b 100644 --- a/packages/runtime-vapor/__tests__/componentSlots.spec.ts +++ b/packages/runtime-vapor/__tests__/componentSlots.spec.ts @@ -469,6 +469,43 @@ describe('component: slots', () => { expect(html()).toBe('content') }) + test('use fallback on initial render', async () => { + const Child = { + setup() { + return createSlot('default', null, () => + document.createTextNode('fallback'), + ) + }, + } + + const toggle = ref(false) + + const { html } = define({ + setup() { + return createComponent(Child, null, { + default: () => { + return createIf( + () => toggle.value, + () => { + return document.createTextNode('content') + }, + ) + }, + }) + }, + }).render() + + expect(html()).toBe('fallback') + + toggle.value = true + await nextTick() + expect(html()).toBe('content') + + toggle.value = false + await nextTick() + expect(html()).toBe('fallback') + }) + test('dynamic slot work with v-if', async () => { const val = ref('header') const toggle = ref(false) diff --git a/packages/runtime-vapor/src/componentSlots.ts b/packages/runtime-vapor/src/componentSlots.ts index 74296e09466..8b9a078d90b 100644 --- a/packages/runtime-vapor/src/componentSlots.ts +++ b/packages/runtime-vapor/src/componentSlots.ts @@ -1,5 +1,11 @@ import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared' -import { type Block, type BlockFn, DynamicFragment, insert } from './block' +import { + type Block, + type BlockFn, + DynamicFragment, + insert, + isValidBlock, +} from './block' import { rawPropsProxyHandlers } from './componentProps' import { currentInstance, isRef } from '@vue/runtime-dom' import type { LooseRawProps, VaporComponentInstance } from './component' @@ -127,7 +133,13 @@ export function createSlot( (slot._bound = () => { const slotContent = slot(slotProps) if (slotContent instanceof DynamicFragment) { - slotContent.fallback = fallback + if ( + (slotContent.fallback = fallback) && + !isValidBlock(slotContent.nodes) + ) { + // use fallback if the slot content is invalid + slotContent.update(fallback) + } } return slotContent }),