]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): hydration for transition wrapper components with empty slot content (#5995)
author小刘(liulinboyi) <814921718@qq.com>
Mon, 6 Jun 2022 08:24:40 +0000 (16:24 +0800)
committerGitHub <noreply@github.com>
Mon, 6 Jun 2022 08:24:40 +0000 (04:24 -0400)
fix #5991

packages/compiler-ssr/__tests__/ssrSlotOutlet.spec.ts
packages/compiler-ssr/src/transforms/ssrTransformSlotOutlet.ts
packages/server-renderer/__tests__/ssrSlot.spec.ts
packages/server-renderer/src/helpers/ssrRenderSlot.ts

index 695cfdf7f133937688d70a58eba8589ab155bdf3..21fbe649c4afec065fcbea74d24e69f42a51376b 100644 (file)
@@ -123,7 +123,7 @@ describe('ssr: <slot>', () => {
       "const { ssrRenderSlotInner: _ssrRenderSlotInner } = require(\\"vue/server-renderer\\")
 
       return function ssrRender(_ctx, _push, _parent, _attrs) {
-        _ssrRenderSlotInner(_ctx.$slots, \\"default\\", {}, null, _push, _parent)
+        _ssrRenderSlotInner(_ctx.$slots, \\"default\\", {}, null, _push, _parent, null, true)
       }"
     `)
   })
index 3486f3551021667a14a9aadd42c3949296310769..c4bbb6ff620d89744e0d93ddbae0c4a8390d72ba 100644 (file)
@@ -50,6 +50,10 @@ export const ssrTransformSlotOutlet: NodeTransform = (node, context) => {
       parent.children.filter(c => c.type === NodeTypes.ELEMENT).length === 1
     ) {
       method = SSR_RENDER_SLOT_INNER
+      if (!(context.scopeId && context.slotted !== false)) {
+        args.push('null')
+      }
+      args.push('true')
     }
 
     node.ssrCodegenNode = createCallExpression(context.helper(method), args)
index baf8f227806b33b67d74c312dcbee3b81c8cfaf6..9b93a55c0f0c4da2c768bd55dd557fe42fc92b16 100644 (file)
@@ -113,4 +113,32 @@ describe('ssr: slot', () => {
       `<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>`)
+  })
 })
index 8f746ec1e471fcdf34c41d914cf167009dc88683..fbe7266b2a1050d6f9654ac960eab7905cad6b6f 100644 (file)
@@ -40,7 +40,8 @@ export function ssrRenderSlotInner(
   fallbackRenderFn: (() => void) | null,
   push: PushFn,
   parentComponent: ComponentInternalInstance,
-  slotScopeId?: string
+  slotScopeId?: string,
+  transition?: boolean
 ) {
   const slotFn = slots[slotName]
   if (slotFn) {
@@ -61,10 +62,14 @@ export function ssrRenderSlotInner(
       // 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 (transition) {
+        isEmptySlot = false
+      } else {
+        for (let i = 0; i < slotBuffer.length; i++) {
+          if (!isComment(slotBuffer[i])) {
+            isEmptySlot = false
+            break
+          }
         }
       }
       if (isEmptySlot) {