fix(ssr): hydration for transition wrapper components with empty slot content (#5995)

fix #5991
This commit is contained in:
小刘(liulinboyi) 2022-06-06 16:24:40 +08:00 committed by GitHub
parent 0cf9ae62be
commit eb22a62798
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 6 deletions

View File

@ -123,7 +123,7 @@ describe('ssr: <slot>', () => {
"const { ssrRenderSlotInner: _ssrRenderSlotInner } = require(\\"vue/server-renderer\\") "const { ssrRenderSlotInner: _ssrRenderSlotInner } = require(\\"vue/server-renderer\\")
return function ssrRender(_ctx, _push, _parent, _attrs) { return function ssrRender(_ctx, _push, _parent, _attrs) {
_ssrRenderSlotInner(_ctx.$slots, \\"default\\", {}, null, _push, _parent) _ssrRenderSlotInner(_ctx.$slots, \\"default\\", {}, null, _push, _parent, null, true)
}" }"
`) `)
}) })

View File

@ -50,6 +50,10 @@ export const ssrTransformSlotOutlet: NodeTransform = (node, context) => {
parent.children.filter(c => c.type === NodeTypes.ELEMENT).length === 1 parent.children.filter(c => c.type === NodeTypes.ELEMENT).length === 1
) { ) {
method = SSR_RENDER_SLOT_INNER method = SSR_RENDER_SLOT_INNER
if (!(context.scopeId && context.slotted !== false)) {
args.push('null')
}
args.push('true')
} }
node.ssrCodegenNode = createCallExpression(context.helper(method), args) node.ssrCodegenNode = createCallExpression(context.helper(method), args)

View File

@ -113,4 +113,32 @@ describe('ssr: slot', () => {
`<div><!--[--><!--[--><div>one</div><div>two</div><!--]--><!--]--></div>` `<div><!--[--><!--[--><div>one</div><div>two</div><!--]--><!--]--></div>`
) )
}) })
test('transition slot', async () => {
expect(
await renderToString(
createApp({
components: {
one: {
template: `<transition><slot/></transition>`
}
},
template: `<one><div v-if="false">foo</div></one>`
})
)
).toBe(`<!---->`)
expect(
await renderToString(
createApp({
components: {
one: {
template: `<transition><slot/></transition>`
}
},
template: `<one><div v-if="true">foo</div></one>`
})
)
).toBe(`<div>foo</div>`)
})
}) })

View File

@ -40,7 +40,8 @@ export function ssrRenderSlotInner(
fallbackRenderFn: (() => void) | null, fallbackRenderFn: (() => void) | null,
push: PushFn, push: PushFn,
parentComponent: ComponentInternalInstance, parentComponent: ComponentInternalInstance,
slotScopeId?: string slotScopeId?: string,
transition?: boolean
) { ) {
const slotFn = slots[slotName] const slotFn = slots[slotName]
if (slotFn) { if (slotFn) {
@ -61,10 +62,14 @@ export function ssrRenderSlotInner(
// 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
let isEmptySlot = true let isEmptySlot = true
for (let i = 0; i < slotBuffer.length; i++) { if (transition) {
if (!isComment(slotBuffer[i])) { isEmptySlot = false
isEmptySlot = false } else {
break for (let i = 0; i < slotBuffer.length; i++) {
if (!isComment(slotBuffer[i])) {
isEmptySlot = false
break
}
} }
} }
if (isEmptySlot) { if (isEmptySlot) {