diff --git a/packages/server-renderer/__tests__/ssrSlot.spec.ts b/packages/server-renderer/__tests__/ssrSlot.spec.ts
index 4534630879f..7e2b2247d25 100644
--- a/packages/server-renderer/__tests__/ssrSlot.spec.ts
+++ b/packages/server-renderer/__tests__/ssrSlot.spec.ts
@@ -137,4 +137,20 @@ describe('ssr: slot', () => {
),
).toBe(`
foo
`)
})
+
+ // #9933
+ test('transition-group slot', async () => {
+ expect(
+ await renderToString(
+ createApp({
+ components: {
+ one: {
+ template: ``,
+ },
+ },
+ template: `{{i}}
`,
+ }),
+ ),
+ ).toBe(``)
+ })
})
diff --git a/packages/server-renderer/src/helpers/ssrRenderSlot.ts b/packages/server-renderer/src/helpers/ssrRenderSlot.ts
index b388e7d1936..df088e8929a 100644
--- a/packages/server-renderer/src/helpers/ssrRenderSlot.ts
+++ b/packages/server-renderer/src/helpers/ssrRenderSlot.ts
@@ -82,7 +82,23 @@ export function ssrRenderSlotInner(
fallbackRenderFn()
}
} else {
- for (let i = 0; i < slotBuffer.length; i++) {
+ // #9933
+ // Although we handle Transition/TransitionGroup in the transform stage
+ // without rendering it as a fragment, the content passed into the slot
+ // may still be a fragment.
+ // Therefore, here we need to avoid rendering it as a fragment again.
+ let start = 0
+ let end = slotBuffer.length
+ if (
+ transition &&
+ slotBuffer[0] === '' &&
+ slotBuffer[end - 1] === ''
+ ) {
+ start++
+ end--
+ }
+
+ for (let i = start; i < end; i++) {
push(slotBuffer[i])
}
}