Skip to content

Commit 88f6b33

Browse files
committed
fix(ssr): properly handle ssr empty slot and fallback
1 parent 02493a4 commit 88f6b33

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

packages/server-renderer/src/helpers/ssrRenderSlot.ts

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ComponentInternalInstance, Slots } from 'vue'
2-
import { Props, PushFn, renderVNodeChildren } from '../render'
2+
import { Props, PushFn, renderVNodeChildren, SSRBufferItem } from '../render'
33

44
export type SSRSlots = Record<string, SSRSlot>
55
export type SSRSlot = (
@@ -22,18 +22,46 @@ export function ssrRenderSlot(
2222
const slotFn = slots[slotName]
2323
if (slotFn) {
2424
const scopeId = parentComponent && parentComponent.type.__scopeId
25+
const slotBuffer: SSRBufferItem[] = []
26+
const bufferedPush = (item: SSRBufferItem) => {
27+
slotBuffer.push(item)
28+
}
2529
const ret = slotFn(
2630
slotProps,
27-
push,
31+
bufferedPush,
2832
parentComponent,
2933
scopeId ? ` ${scopeId}-s` : ``
3034
)
3135
if (Array.isArray(ret)) {
3236
// normal slot
3337
renderVNodeChildren(push, ret, parentComponent)
38+
} else {
39+
// ssr slot.
40+
// check if the slot renders all comments, in which case use the fallback
41+
let isEmptySlot = true
42+
for (let i = 0; i < slotBuffer.length; i++) {
43+
if (!isComment(slotBuffer[i])) {
44+
isEmptySlot = false
45+
break
46+
}
47+
}
48+
if (isEmptySlot) {
49+
if (fallbackRenderFn) {
50+
fallbackRenderFn()
51+
}
52+
} else {
53+
for (let i = 0; i < slotBuffer.length; i++) {
54+
push(slotBuffer[i])
55+
}
56+
}
3457
}
3558
} else if (fallbackRenderFn) {
3659
fallbackRenderFn()
3760
}
3861
push(`<!--]-->`)
3962
}
63+
64+
const commentRE = /^<!--.*-->$/
65+
function isComment(item: SSRBufferItem) {
66+
return typeof item === 'string' && commentRE.test(item)
67+
}

0 commit comments

Comments
 (0)