]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): avoid traversing static children for vnodes w/ PatchFlags.BAIL...
authorTycho <jh.leong@outlook.com>
Fri, 14 Jun 2024 09:10:13 +0000 (17:10 +0800)
committerGitHub <noreply@github.com>
Fri, 14 Jun 2024 09:10:13 +0000 (17:10 +0800)
close #10547

packages/runtime-core/__tests__/rendererFragment.spec.ts
packages/runtime-core/src/renderer.ts

index 5f1e869366fb0dc4c132b0771aaed84d7ff38bd5..81cf7b8df31e98d5d0e0d423c2e4f2a1c2229b8d 100644 (file)
@@ -3,6 +3,7 @@ import {
   NodeOpTypes,
   type TestElement,
   TestNodeTypes,
+  type VNode,
   createBlock,
   createCommentVNode,
   createTextVNode,
@@ -316,6 +317,64 @@ describe('renderer: fragment', () => {
     )
   })
 
+  // #10547
+  test('`template` fragment w/ render function', () => {
+    const renderFn = (vnode: VNode) => {
+      return (
+        openBlock(),
+        createBlock(
+          Fragment,
+          null,
+          [createTextVNode('text'), (openBlock(), createBlock(vnode))],
+          PatchFlags.STABLE_FRAGMENT,
+        )
+      )
+    }
+
+    const root = nodeOps.createElement('div')
+    const foo = h('div', ['foo'])
+    const bar = h('div', [h('div', 'bar')])
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div>foo</div>`)
+
+    render(renderFn(bar), root)
+    expect(serializeInner(root)).toBe(`text<div><div>bar</div></div>`)
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div>foo</div>`)
+  })
+
+  // #10547
+  test('`template` fragment w/ render function + keyed vnode', () => {
+    const renderFn = (vnode: VNode) => {
+      return (
+        openBlock(),
+        createBlock(
+          Fragment,
+          null,
+          [createTextVNode('text'), (openBlock(), createBlock(vnode))],
+          PatchFlags.STABLE_FRAGMENT,
+        )
+      )
+    }
+
+    const root = nodeOps.createElement('div')
+    const foo = h('div', { key: 1 }, [h('div', 'foo')])
+    const bar = h('div', { key: 2 }, [h('div', 'bar'), h('div', 'bar')])
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div><div>foo</div></div>`)
+
+    render(renderFn(bar), root)
+    expect(serializeInner(root)).toBe(
+      `text<div><div>bar</div><div>bar</div></div>`,
+    )
+
+    render(renderFn(foo), root)
+    expect(serializeInner(root)).toBe(`text<div><div>foo</div></div>`)
+  })
+
   // #6852
   test('`template` keyed fragment w/ text', () => {
     const root = nodeOps.createElement('div')
index 2a35a5e192538a4f4c0c6247a4ff41df4126869c..ccb89085c40969aaaeb92ce76b581d2dea476a89 100644 (file)
@@ -2473,7 +2473,8 @@ export function traverseStaticChildren(n1: VNode, n2: VNode, shallow = false) {
           c2 = ch2[i] = cloneIfMounted(ch2[i] as VNode)
           c2.el = c1.el
         }
-        if (!shallow) traverseStaticChildren(c1, c2)
+        if (!shallow && c2.patchFlag !== PatchFlags.BAIL)
+          traverseStaticChildren(c1, c2)
       }
       // #6852 also inherit for text nodes
       if (c2.type === Text) {