Browse Source

fix(ssr): avoid rendering transition-group slot content as a fragment (#9961)

close #9933
edison 2 years ago
parent
commit
0160264d67

+ 16 - 0
packages/server-renderer/__tests__/ssrSlot.spec.ts

@@ -137,4 +137,20 @@ describe('ssr: slot', () => {
       ),
     ).toBe(`<div>foo</div>`)
   })
+
+  // #9933
+  test('transition-group slot', async () => {
+    expect(
+      await renderToString(
+        createApp({
+          components: {
+            one: {
+              template: `<TransitionGroup tag="div"><slot/></TransitionGroup>`,
+            },
+          },
+          template: `<one><p v-for="i in 2">{{i}}</p></one>`,
+        }),
+      ),
+    ).toBe(`<div><p>1</p><p>2</p></div>`)
+  })
 })

+ 17 - 1
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])
         }
       }