diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts index eaef8d401a7..47560c41ca4 100644 --- a/packages/runtime-core/__tests__/hmr.spec.ts +++ b/packages/runtime-core/__tests__/hmr.spec.ts @@ -151,6 +151,44 @@ describe('hot module replacement', () => { expect(mountSpy).toHaveBeenCalledTimes(1) }) + test('reload KeepAlive slot', async () => { + const root = nodeOps.createElement('div') + const childId = 'test-child-keep-alive' + const unmountSpy = jest.fn() + const mountSpy = jest.fn() + + const Child: ComponentOptions = { + __hmrId: childId, + data() { + return { count: 0 } + }, + unmounted: unmountSpy, + render: compileToFunction(`
{{ count }}
`) + } + createRecord(childId, Child) + + const Parent: ComponentOptions = { + components: { Child }, + render: compileToFunction(``) + } + + render(h(Parent), root) + expect(serializeInner(root)).toBe(`
0
`) + + reload(childId, { + __hmrId: childId, + data() { + return { count: 1 } + }, + mounted: mountSpy, + render: compileToFunction(`
{{ count }}
`) + }) + await nextTick() + expect(serializeInner(root)).toBe(`
1
`) + expect(unmountSpy).toHaveBeenCalledTimes(1) + expect(mountSpy).toHaveBeenCalledTimes(1) + }) + test('reload class component', async () => { const root = nodeOps.createElement('div') const childId = 'test4-child' diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 2122f9f855a..36b95d0b0bf 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -352,6 +352,14 @@ export function isSameVNodeType(n1: VNode, n2: VNode): boolean { n2.shapeFlag & ShapeFlags.COMPONENT && hmrDirtyComponents.has(n2.type as ConcreteComponent) ) { + // #7042, ensure the vnode being unmounted during HMR + if (n1.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) { + n1.shapeFlag -= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE + } + // #7042, ensure the vnode being mounted as fresh during HMR + if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) { + n2.shapeFlag -= ShapeFlags.COMPONENT_KEPT_ALIVE + } // HMR only: if the component has been hot-updated, force a reload. return false }