]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(ssr): fix hydration for slot with empty text node
authorEvan You <yyx990803@gmail.com>
Thu, 19 May 2022 04:35:29 +0000 (12:35 +0800)
committerEvan You <yyx990803@gmail.com>
Thu, 19 May 2022 04:35:29 +0000 (12:35 +0800)
fix #5728

packages/runtime-core/__tests__/hydration.spec.ts
packages/runtime-core/src/hydration.ts

index 58661233564c81f56d7861db8ea247096f465879..34e76100ee4991181e16aa31648bdabe0e75d499 100644 (file)
@@ -13,7 +13,8 @@ import {
   createTextVNode,
   createVNode,
   withDirectives,
-  vModelCheckbox
+  vModelCheckbox,
+  renderSlot
 } from '@vue/runtime-dom'
 import { renderToString, SSRContext } from '@vue/server-renderer'
 import { PatchFlags } from '../../shared/src'
@@ -912,6 +913,24 @@ describe('SSR hydration', () => {
     expect((container.firstChild!.firstChild as any)._value).toBe(true)
   })
 
+  // #5728
+  test('empty text node in slot', () => {
+    const Comp = {
+      render(this: any) {
+        return renderSlot(this.$slots, 'default', {}, () => [
+          createTextVNode('')
+        ])
+      }
+    }
+    const { container, vnode } = mountWithHydration('<!--[--><!--]-->', () => h(Comp))
+    expect(container.childNodes.length).toBe(3)
+    const text = container.childNodes[1]
+    expect(text.nodeType).toBe(3)
+    expect(vnode.el).toBe(container.childNodes[0])
+    // component => slot fragment => text node
+    expect((vnode as any).component?.subTree.children[0].el).toBe(text)
+  })
+
   describe('mismatch handling', () => {
     test('text node', () => {
       const { container } = mountWithHydration(`foo`, () => 'bar')
index fcc22897f5c4737e7910961157ec9ef71ac195c9..a8a568cabb0c58a67deb192a7a9171c46c1c00cf 100644 (file)
@@ -110,7 +110,18 @@ export function createHydrationFunctions(
     switch (type) {
       case Text:
         if (domType !== DOMNodeTypes.TEXT) {
-          nextNode = onMismatch()
+          // #5728 empty text node inside a slot can cause hydration failure
+          // because the server rendered HTML won't contain a text node
+          if (vnode.children === '') {
+            insert(
+              (vnode.el = document.createTextNode('')),
+              node.parentElement!,
+              node
+            )
+            nextNode = node
+          } else {
+            nextNode = onMismatch()
+          }
         } else {
           if ((node as Text).data !== vnode.children) {
             hasMismatch = true