mirror of https://github.com/vuejs/core.git
fix(ssr): ensure content is valid when rendering normal slot (#11491)
fix #11326
This commit is contained in:
parent
fdc2a31dbd
commit
6c90324870
|
|
@ -87,7 +87,7 @@ export function renderSlot(
|
||||||
return rendered
|
return rendered
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureValidVNode(vnodes: VNodeArrayChildren) {
|
export function ensureValidVNode(vnodes: VNodeArrayChildren) {
|
||||||
return vnodes.some(child => {
|
return vnodes.some(child => {
|
||||||
if (!isVNode(child)) return true
|
if (!isVNode(child)) return true
|
||||||
if (child.type === Comment) return false
|
if (child.type === Comment) return false
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ import {
|
||||||
import { renderComponentRoot } from './componentRenderUtils'
|
import { renderComponentRoot } from './componentRenderUtils'
|
||||||
import { setCurrentRenderingInstance } from './componentRenderContext'
|
import { setCurrentRenderingInstance } from './componentRenderContext'
|
||||||
import { isVNode, normalizeVNode } from './vnode'
|
import { isVNode, normalizeVNode } from './vnode'
|
||||||
|
import { ensureValidVNode } from './helpers/renderSlot'
|
||||||
|
|
||||||
const _ssrUtils = {
|
const _ssrUtils = {
|
||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
|
|
@ -380,6 +381,7 @@ const _ssrUtils = {
|
||||||
isVNode,
|
isVNode,
|
||||||
normalizeVNode,
|
normalizeVNode,
|
||||||
getComponentPublicInstance,
|
getComponentPublicInstance,
|
||||||
|
ensureValidVNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -153,4 +153,54 @@ describe('ssr: slot', () => {
|
||||||
),
|
),
|
||||||
).toBe(`<div><p>1</p><p>2</p></div>`)
|
).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>`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { ComponentInternalInstance, Slots } from 'vue'
|
import { type ComponentInternalInstance, type Slots, ssrUtils } from 'vue'
|
||||||
import {
|
import {
|
||||||
type Props,
|
type Props,
|
||||||
type PushFn,
|
type PushFn,
|
||||||
|
|
@ -7,6 +7,8 @@ import {
|
||||||
} from '../render'
|
} from '../render'
|
||||||
import { isArray } from '@vue/shared'
|
import { isArray } from '@vue/shared'
|
||||||
|
|
||||||
|
const { ensureValidVNode } = ssrUtils
|
||||||
|
|
||||||
export type SSRSlots = Record<string, SSRSlot>
|
export type SSRSlots = Record<string, SSRSlot>
|
||||||
export type SSRSlot = (
|
export type SSRSlot = (
|
||||||
props: Props,
|
props: Props,
|
||||||
|
|
@ -61,8 +63,18 @@ export function ssrRenderSlotInner(
|
||||||
slotScopeId ? ' ' + slotScopeId : '',
|
slotScopeId ? ' ' + slotScopeId : '',
|
||||||
)
|
)
|
||||||
if (isArray(ret)) {
|
if (isArray(ret)) {
|
||||||
|
const validSlotContent = ensureValidVNode(ret)
|
||||||
|
if (validSlotContent) {
|
||||||
// normal slot
|
// normal slot
|
||||||
renderVNodeChildren(push, ret, parentComponent, slotScopeId)
|
renderVNodeChildren(
|
||||||
|
push,
|
||||||
|
validSlotContent,
|
||||||
|
parentComponent,
|
||||||
|
slotScopeId,
|
||||||
|
)
|
||||||
|
} else if (fallbackRenderFn) {
|
||||||
|
fallbackRenderFn()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// ssr slot.
|
// ssr slot.
|
||||||
// check if the slot renders all comments, in which case use the fallback
|
// check if the slot renders all comments, in which case use the fallback
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue