diff --git a/packages/server-renderer/src/helpers/ssrRenderSlot.ts b/packages/server-renderer/src/helpers/ssrRenderSlot.ts index 6231b189525..5ee6113a198 100644 --- a/packages/server-renderer/src/helpers/ssrRenderSlot.ts +++ b/packages/server-renderer/src/helpers/ssrRenderSlot.ts @@ -1,5 +1,5 @@ import { ComponentInternalInstance, Slots } from 'vue' -import { Props, PushFn, renderVNodeChildren } from '../render' +import { Props, PushFn, renderVNodeChildren, SSRBufferItem } from '../render' export type SSRSlots = Record export type SSRSlot = ( @@ -22,18 +22,46 @@ export function ssrRenderSlot( const slotFn = slots[slotName] if (slotFn) { const scopeId = parentComponent && parentComponent.type.__scopeId + const slotBuffer: SSRBufferItem[] = [] + const bufferedPush = (item: SSRBufferItem) => { + slotBuffer.push(item) + } const ret = slotFn( slotProps, - push, + bufferedPush, parentComponent, scopeId ? ` ${scopeId}-s` : `` ) if (Array.isArray(ret)) { // normal slot renderVNodeChildren(push, ret, parentComponent) + } else { + // ssr slot. + // check if the slot renders all comments, in which case use the fallback + let isEmptySlot = true + for (let i = 0; i < slotBuffer.length; i++) { + if (!isComment(slotBuffer[i])) { + isEmptySlot = false + break + } + } + if (isEmptySlot) { + if (fallbackRenderFn) { + fallbackRenderFn() + } + } else { + for (let i = 0; i < slotBuffer.length; i++) { + push(slotBuffer[i]) + } + } } } else if (fallbackRenderFn) { fallbackRenderFn() } push(``) } + +const commentRE = /^$/ +function isComment(item: SSRBufferItem) { + return typeof item === 'string' && commentRE.test(item) +}