fix(runtime-vapor): render slot fallback if slot content is not a valid block
ci / test (push) Waiting to run Details
ci / continuous-release (push) Waiting to run Details

close #13668
This commit is contained in:
daiwei 2025-07-21 08:29:31 +08:00
parent 56a7f9dd18
commit b498eecba5
3 changed files with 68 additions and 3 deletions

View File

@ -502,5 +502,64 @@ describe('component: slots', () => {
await nextTick()
expect(host.innerHTML).toBe('<div><h1></h1><!--slot--></div>')
})
test('render fallback when slot content is not valid', async () => {
const Child = {
setup() {
return createSlot('default', null, () =>
document.createTextNode('fallback'),
)
},
}
const { html } = define({
setup() {
return createComponent(Child, null, {
default: () => {
return template('<!--comment-->')()
},
})
},
}).render()
expect(html()).toBe('fallback<!--slot-->')
})
test('render fallback when v-if condition is false', 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<!--if--><!--slot-->')
toggle.value = true
await nextTick()
expect(html()).toBe('content<!--if--><!--slot-->')
toggle.value = false
await nextTick()
expect(html()).toBe('fallback<!--if--><!--slot-->')
})
})
})

View File

@ -67,9 +67,14 @@ export class DynamicFragment extends VaporFragment {
if (this.fallback && !isValidBlock(this.nodes)) {
parent && remove(this.nodes, parent)
this.nodes =
(this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
[]
// render fallback for dynamic fragment
if (this.nodes instanceof DynamicFragment) {
this.nodes.update(this.fallback)
} else {
this.nodes =
(this.scope || (this.scope = new EffectScope())).run(this.fallback) ||
[]
}
parent && insert(this.nodes, parent, this.anchor)
}

View File

@ -126,6 +126,7 @@ export function createSlot(
const renderSlot = () => {
const slot = getSlot(rawSlots, isFunction(name) ? name() : name)
if (slot) {
fragment.fallback = fallback
// create and cache bound version of the slot to make it stable
// so that we avoid unnecessary updates if it resolves to the same slot
fragment.update(