]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hydration): handling empty text nodes edison/testVapor 13383/head
authordaiwei <daiwei521@126.com>
Tue, 5 Aug 2025 13:04:51 +0000 (21:04 +0800)
committerdaiwei <daiwei521@126.com>
Tue, 5 Aug 2025 13:04:51 +0000 (21:04 +0800)
packages/compiler-vapor/src/generators/text.ts
packages/runtime-vapor/__tests__/hydration.spec.ts
packages/runtime-vapor/src/dom/node.ts

index 1f706ebd1229b2702797dc6deb48bb030115870a..75faf3f57f348bdcd09ed3032590883dcbb75976 100644 (file)
@@ -70,6 +70,6 @@ export function genGetTextChild(
 
   return [
     NEWLINE,
-    `const x${oper.parent} = ${context.helper('child')}(n${oper.parent})`,
+    `const x${oper.parent} = ${context.helper('child')}(n${oper.parent}, -1)`,
   ]
 }
index 5ff4cbf51f4ee06346881e1805c8588e059d89ca..26da9e3e746b6c70fee7ff3b6bec1a751e5afa65 100644 (file)
@@ -182,6 +182,20 @@ describe('Vapor Mode hydration', () => {
         `"<!--[--><span></span>barAbarBbar<span></span><!--]-->"`,
       )
     })
+
+    test('empty text nodes', async () => {
+      const data = reactive({ txt: '' })
+      const { container } = await testHydration(
+        `<template><div>{{ data.txt }}</div></template>`,
+        undefined,
+        data,
+      )
+      expect(container.innerHTML).toMatchInlineSnapshot(`"<div> </div>"`)
+
+      data.txt = 'foo'
+      await nextTick()
+      expect(container.innerHTML).toMatchInlineSnapshot(`"<div>foo</div>"`)
+    })
   })
 
   describe('element', () => {
index 7622c1676d0b799abae6cd0489a9f6cd44e3f02d..71b270868b0c25e4dd5ef65595cbfc9cf290ccda 100644 (file)
@@ -60,15 +60,23 @@ export function _child(node: ParentNode): Node {
  */
 /*! #__NO_SIDE_EFFECTS__ */
 export function __child(node: ParentNode, offset?: number): Node {
-  let n = offset ? __nthChild(node, offset) : node.firstChild!
-
-  if (isComment(n, '[')) {
-    n = locateEndAnchor(n)!.nextSibling!
+  // when offset is -1, it means we need to get the text node of this element
+  // since server-side rendering doesn't generate whitespace placeholder text nodes,
+  // if firstChild is null, manually insert a text node and return it
+  if (offset === -1 && !node.firstChild) {
+    node.textContent = ' '
+    return node.firstChild!
   }
 
-  while (n && isVaporAnchors(n)) {
-    n = n.nextSibling!
+  let n = offset ? __nthChild(node, offset) : node.firstChild!
+  while (n && (isComment(n, '[') || isVaporAnchors(n))) {
+    if (isComment(n, '[')) {
+      n = locateEndAnchor(n)!.nextSibling!
+    } else {
+      n = n.nextSibling!
+    }
   }
+
   return n
 }