Skip to content

Commit 8602be2

Browse files
committed
fix(runtime-vapor): render slot fallback if slot content is not a valid block
close #13668
1 parent 56a7f9d commit 8602be2

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

packages/runtime-vapor/__tests__/componentSlots.spec.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,5 +502,64 @@ describe('component: slots', () => {
502502
await nextTick()
503503
expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
504504
})
505+
506+
test('render fallback when slot content is not valid', async () => {
507+
const Child = {
508+
setup() {
509+
return createSlot('default', null, () =>
510+
document.createTextNode('fallback'),
511+
)
512+
},
513+
}
514+
515+
const { html } = define({
516+
setup() {
517+
return createComponent(Child, null, {
518+
default: () => {
519+
return template('<!--comment-->')()
520+
},
521+
})
522+
},
523+
}).render()
524+
525+
expect(html()).toBe('fallback<!--slot-->')
526+
})
527+
528+
test('render fallback when v-if condition is false', async () => {
529+
const Child = {
530+
setup() {
531+
return createSlot('default', null, () =>
532+
document.createTextNode('fallback'),
533+
)
534+
},
535+
}
536+
537+
const toggle = ref(false)
538+
539+
const { html } = define({
540+
setup() {
541+
return createComponent(Child, null, {
542+
default: () => {
543+
return createIf(
544+
() => toggle.value,
545+
() => {
546+
return document.createTextNode('content')
547+
},
548+
)
549+
},
550+
})
551+
},
552+
}).render()
553+
554+
expect(html()).toBe('fallback<!--if--><!--slot-->')
555+
556+
toggle.value = true
557+
await nextTick()
558+
expect(html()).toBe('content<!--if--><!--slot-->')
559+
560+
toggle.value = false
561+
await nextTick()
562+
expect(html()).toBe('fallback<!--if--><!--slot-->')
563+
})
505564
})
506565
})

packages/runtime-vapor/src/componentSlots.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { EMPTY_OBJ, NO, hasOwn, isArray, isFunction } from '@vue/shared'
2-
import { type Block, type BlockFn, DynamicFragment, insert } from './block'
2+
import {
3+
type Block,
4+
type BlockFn,
5+
DynamicFragment,
6+
insert,
7+
isValidBlock,
8+
} from './block'
39
import { rawPropsProxyHandlers } from './componentProps'
410
import { currentInstance, isRef } from '@vue/runtime-dom'
511
import type { LooseRawProps, VaporComponentInstance } from './component'
@@ -126,14 +132,21 @@ export function createSlot(
126132
const renderSlot = () => {
127133
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
128134
if (slot) {
135+
fragment.fallback = fallback
129136
// create and cache bound version of the slot to make it stable
130137
// so that we avoid unnecessary updates if it resolves to the same slot
131138
fragment.update(
132139
slot._bound ||
133140
(slot._bound = () => {
134141
const slotContent = slot(slotProps)
135142
if (slotContent instanceof DynamicFragment) {
136-
slotContent.fallback = fallback
143+
// render fallback if slot content is not a valid block
144+
if (
145+
(slotContent.fallback = fallback) &&
146+
!isValidBlock(slotContent.nodes)
147+
) {
148+
slotContent.update(fallback)
149+
}
137150
}
138151
return slotContent
139152
}),

0 commit comments

Comments
 (0)