diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts
index ba9c7c0780b..3f157d009a9 100644
--- a/packages/runtime-core/__tests__/hmr.spec.ts
+++ b/packages/runtime-core/__tests__/hmr.spec.ts
@@ -851,4 +851,47 @@ describe('hot module replacement', () => {
expect(serializeInner(root)).toBe(`
1
1
`)
})
+
+ test('reload async child wrapped in Suspense + KeepAlive', async () => {
+ const id = 'async-child-reload'
+ const AsyncChild: ComponentOptions = {
+ __hmrId: id,
+ async setup() {
+ await nextTick()
+ return () => 'foo'
+ },
+ }
+ createRecord(id, AsyncChild)
+
+ const appId = 'test-app-id'
+ const App: ComponentOptions = {
+ __hmrId: appId,
+ components: { AsyncChild },
+ render: compileToFunction(`
+
+ `),
+ }
+
+ const root = nodeOps.createElement('div')
+ render(h(App), root)
+ expect(serializeInner(root)).toBe('')
+ await timeout()
+ expect(serializeInner(root)).toBe('foo
')
+
+ reload(id, {
+ __hmrId: id,
+ async setup() {
+ await nextTick()
+ return () => 'bar'
+ },
+ })
+ await timeout()
+ expect(serializeInner(root)).toBe('bar
')
+ })
})
diff --git a/packages/runtime-core/src/hmr.ts b/packages/runtime-core/src/hmr.ts
index 0adf4fd4329..7aedf52dd3e 100644
--- a/packages/runtime-core/src/hmr.ts
+++ b/packages/runtime-core/src/hmr.ts
@@ -144,7 +144,9 @@ function reload(id: string, newComp: HMRComponent): void {
// components to be unmounted and re-mounted. Queue the update so that we
// don't end up forcing the same parent to re-render multiple times.
queueJob(() => {
+ isHmrUpdating = true
instance.parent!.update()
+ isHmrUpdating = false
// #6930, #11248 avoid infinite recursion
dirtyInstances.delete(instance)
})
diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts
index 9b50dca23f9..90cc22f5470 100644
--- a/packages/runtime-core/src/renderer.ts
+++ b/packages/runtime-core/src/renderer.ts
@@ -1211,6 +1211,9 @@ function baseCreateRenderer(
// setup() is async. This component relies on async logic to be resolved
// before proceeding
if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
+ // avoid hydration for hmr updating
+ if (__DEV__ && isHmrUpdating) initialVNode.el = null
+
parentSuspense &&
parentSuspense.registerDep(instance, setupRenderEffect, optimized)