From 5d75a170c8d23acd11ef2513173d4cbc4d0b54de Mon Sep 17 00:00:00 2001
From: yangxiuxiu <79584569+yangxiuxiu1115@users.noreply.github.com>
Date: Tue, 2 Sep 2025 17:44:13 +0800
Subject: [PATCH] fix(Suspence): handle Suspense + KeepAlive HMR updating edge
case (#13076)
close #13075
---
packages/runtime-core/__tests__/hmr.spec.ts | 52 +++++++++++++++++++
.../src/components/BaseTransition.ts | 2 +-
.../runtime-core/src/components/Suspense.ts | 6 +--
3 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts
index e8e0398e17..991cc0ecda 100644
--- a/packages/runtime-core/__tests__/hmr.spec.ts
+++ b/packages/runtime-core/__tests__/hmr.spec.ts
@@ -895,6 +895,58 @@ describe('hot module replacement', () => {
expect(serializeInner(root)).toBe('
bar
')
})
+ 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(`{{ count }}
`),
+ }
+ createRecord(id, Child)
+
+ const appId = 'test-app-id'
+ const App: ComponentOptions = {
+ __hmrId: appId,
+ components: { Child },
+ render: compileToFunction(`
+
+
+
+
+
+ `),
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(App), root)
+ expect(serializeInner(root)).toBe('0
')
+ await timeout()
+ reload(id, {
+ __hmrId: id,
+ setup() {
+ const count = ref(1)
+ return { count }
+ },
+ render: compileToFunction(`{{ count }}
`),
+ })
+ await timeout()
+ expect(serializeInner(root)).toBe('1
')
+
+ reload(id, {
+ __hmrId: id,
+ setup() {
+ const count = ref(2)
+ return { count }
+ },
+ render: compileToFunction(`{{ count }}
`),
+ })
+ await timeout()
+ expect(serializeInner(root)).toBe('2
')
+ })
+
test('rerender for nested component', () => {
const id = 'child-nested-rerender'
const Foo: ComponentOptions = {
diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts
index 698ed428d1..efc34ec1c8 100644
--- a/packages/runtime-core/src/components/BaseTransition.ts
+++ b/packages/runtime-core/src/components/BaseTransition.ts
@@ -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(
diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts
index 85001f500c..0109d77c3f 100644
--- a/packages/runtime-core/src/components/Suspense.ts
+++ b/packages/runtime-core/src/components/Suspense.ts
@@ -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,
--
2.47.3