]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(Suspence): handle Suspense + KeepAlive HMR updating edge case (#13076)
authoryangxiuxiu <79584569+yangxiuxiu1115@users.noreply.github.com>
Tue, 2 Sep 2025 09:44:13 +0000 (17:44 +0800)
committerGitHub <noreply@github.com>
Tue, 2 Sep 2025 09:44:13 +0000 (17:44 +0800)
close #13075

packages/runtime-core/__tests__/hmr.spec.ts
packages/runtime-core/src/components/BaseTransition.ts
packages/runtime-core/src/components/Suspense.ts

index e8e0398e174951e13a4bd10d236e6771333ecce5..991cc0ecdac9c8042727e4ca1a0d900d78e884e1 100644 (file)
@@ -895,6 +895,58 @@ describe('hot module replacement', () => {
     expect(serializeInner(root)).toBe('<div>bar</div>')
   })
 
+  test('multi reload child wrapped in Suspense + KeepAlive', async () => {
+    const id = 'test-child-reload-3'
+    const Child: ComponentOptions = {
+      __hmrId: id,
+      setup() {
+        const count = ref(0)
+        return { count }
+      },
+      render: compileToFunction(`<div>{{ count }}</div>`),
+    }
+    createRecord(id, Child)
+
+    const appId = 'test-app-id'
+    const App: ComponentOptions = {
+      __hmrId: appId,
+      components: { Child },
+      render: compileToFunction(`
+        <KeepAlive>
+          <Suspense>
+            <Child />
+          </Suspense>
+        </KeepAlive>
+      `),
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(App), root)
+    expect(serializeInner(root)).toBe('<div>0</div>')
+    await timeout()
+    reload(id, {
+      __hmrId: id,
+      setup() {
+        const count = ref(1)
+        return { count }
+      },
+      render: compileToFunction(`<div>{{ count }}</div>`),
+    })
+    await timeout()
+    expect(serializeInner(root)).toBe('<div>1</div>')
+
+    reload(id, {
+      __hmrId: id,
+      setup() {
+        const count = ref(2)
+        return { count }
+      },
+      render: compileToFunction(`<div>{{ count }}</div>`),
+    })
+    await timeout()
+    expect(serializeInner(root)).toBe('<div>2</div>')
+  })
+
   test('rerender for nested component', () => {
     const id = 'child-nested-rerender'
     const Foo: ComponentOptions = {
index 698ed428d1ced079861522ac4efc0f4a29d5bc1c..efc34ec1c8f2d4f484e082ec77c5a9435440e290 100644 (file)
@@ -204,7 +204,7 @@ const BaseTransitionImpl: ComponentOptions = {
       if (
         oldInnerChild &&
         oldInnerChild.type !== Comment &&
-        !isSameVNodeType(innerChild, oldInnerChild) &&
+        !isSameVNodeType(oldInnerChild, innerChild) &&
         recursiveGetSubtree(instance).type !== Comment
       ) {
         let leavingHooks = resolveTransitionHooks(
index 85001f500cff8edc027cae4553dd8aa3eee4bed4..0109d77c3f214efc00002bbf8d1a0f4d1d7b5bd6 100644 (file)
@@ -235,7 +235,7 @@ function patchSuspense(
   const { activeBranch, pendingBranch, isInFallback, isHydrating } = suspense
   if (pendingBranch) {
     suspense.pendingBranch = newBranch
-    if (isSameVNodeType(newBranch, pendingBranch)) {
+    if (isSameVNodeType(pendingBranch, newBranch)) {
       // same root type but content may have changed.
       patch(
         pendingBranch,
@@ -321,7 +321,7 @@ function patchSuspense(
           )
           setActiveBranch(suspense, newFallback)
         }
-      } else if (activeBranch && isSameVNodeType(newBranch, activeBranch)) {
+      } else if (activeBranch && isSameVNodeType(activeBranch, newBranch)) {
         // toggled "back" to current active branch
         patch(
           activeBranch,
@@ -355,7 +355,7 @@ function patchSuspense(
       }
     }
   } else {
-    if (activeBranch && isSameVNodeType(newBranch, activeBranch)) {
+    if (activeBranch && isSameVNodeType(activeBranch, newBranch)) {
       // root did not change, just normal patch
       patch(
         activeBranch,