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