return rendered
}
-function ensureValidVNode(vnodes: VNodeArrayChildren) {
+export function ensureValidVNode(vnodes: VNodeArrayChildren) {
return vnodes.some(child => {
if (!isVNode(child)) return true
if (child.type === Comment) return false
import { renderComponentRoot } from './componentRenderUtils'
import { setCurrentRenderingInstance } from './componentRenderContext'
import { isVNode, normalizeVNode } from './vnode'
+import { ensureValidVNode } from './helpers/renderSlot'
const _ssrUtils = {
createComponentInstance,
isVNode,
normalizeVNode,
getComponentPublicInstance,
+ ensureValidVNode,
}
/**
),
).toBe(`<div><p>1</p><p>2</p></div>`)
})
+
+ // #11326
+ test('dynamic component slot', async () => {
+ expect(
+ await renderToString(
+ createApp({
+ components: {
+ ButtonComp: {
+ template: `<component is="button"><slot/></component>`,
+ },
+ Wrap: {
+ template: `<div><slot/></div>`,
+ },
+ },
+ template: `<ButtonComp><Wrap><div v-if="false">hello</div></Wrap></ButtonComp>`,
+ }),
+ ),
+ ).toBe(`<button><!--[--><div><!--[--><!--]--></div><!--]--></button>`)
+
+ expect(
+ await renderToString(
+ createApp({
+ components: {
+ ButtonComp: {
+ template: `<component is="button"><slot/></component>`,
+ },
+ Wrap: {
+ template: `<div><slot/></div>`,
+ },
+ },
+ template: `<ButtonComp><Wrap><div v-if="true">hello</div></Wrap></ButtonComp>`,
+ }),
+ ),
+ ).toBe(
+ `<button><!--[--><div><!--[--><div>hello</div><!--]--></div><!--]--></button>`,
+ )
+
+ expect(
+ await renderToString(
+ createApp({
+ components: {
+ ButtonComp: {
+ template: `<component is="button"><slot/></component>`,
+ },
+ },
+ template: `<ButtonComp><template v-if="false">hello</template></ButtonComp>`,
+ }),
+ ),
+ ).toBe(`<button><!--[--><!--]--></button>`)
+ })
})
-import type { ComponentInternalInstance, Slots } from 'vue'
+import { type ComponentInternalInstance, type Slots, ssrUtils } from 'vue'
import {
type Props,
type PushFn,
} from '../render'
import { isArray } from '@vue/shared'
+const { ensureValidVNode } = ssrUtils
+
export type SSRSlots = Record<string, SSRSlot>
export type SSRSlot = (
props: Props,
slotScopeId ? ' ' + slotScopeId : '',
)
if (isArray(ret)) {
- // normal slot
- renderVNodeChildren(push, ret, parentComponent, slotScopeId)
+ const validSlotContent = ensureValidVNode(ret)
+ if (validSlotContent) {
+ // normal slot
+ renderVNodeChildren(
+ push,
+ validSlotContent,
+ parentComponent,
+ slotScopeId,
+ )
+ } else if (fallbackRenderFn) {
+ fallbackRenderFn()
+ }
} else {
// ssr slot.
// check if the slot renders all comments, in which case use the fallback