From 6575a6e445c10eed7b20d3b0ae366c7730598207 Mon Sep 17 00:00:00 2001 From: Rairn <958414905@qq.com> Date: Mon, 14 Nov 2022 11:34:42 +0800 Subject: [PATCH 1/3] fix(hmr/transition): fix transition elements disappearing after reloading component (#7121) --- packages/runtime-core/__tests__/hmr.spec.ts | 69 +++++++++++++++++++ .../src/components/BaseTransition.ts | 5 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts index db713a3f276..d7c54cdc27d 100644 --- a/packages/runtime-core/__tests__/hmr.spec.ts +++ b/packages/runtime-core/__tests__/hmr.spec.ts @@ -218,6 +218,75 @@ describe('hot module replacement', () => { expect(deactiveSpy).toHaveBeenCalledTimes(1) }) + // #7121 + test('reload KeepAlive slot in Transition', async () => { + const root = nodeOps.createElement('div') + const childId = 'test-transition-keep-alive-reload' + const unmountSpy = jest.fn() + const mountSpy = jest.fn() + const activeSpy = jest.fn() + const deactiveSpy = jest.fn() + + const Child: ComponentOptions = { + __hmrId: childId, + data() { + return { count: 0 } + }, + unmounted: unmountSpy, + render: compileToFunction(`
{{ count }}
`) + } + createRecord(childId, Child) + + const Parent: ComponentOptions = { + components: { Child }, + data() { + return { toggle: true } + }, + render: compileToFunction( + `` + ) + } + + render(h(Parent), root) + expect(serializeInner(root)).toBe(`
0
`) + + reload(childId, { + __hmrId: childId, + data() { + return { count: 1 } + }, + mounted: mountSpy, + unmounted: unmountSpy, + activated: activeSpy, + deactivated: deactiveSpy, + render: compileToFunction(`
{{ count }}
`) + }) + await nextTick() + expect(serializeInner(root)).toBe(`
1
`) + expect(unmountSpy).toHaveBeenCalledTimes(1) + expect(mountSpy).toHaveBeenCalledTimes(1) + expect(activeSpy).toHaveBeenCalledTimes(1) + expect(deactiveSpy).toHaveBeenCalledTimes(0) + + // should not unmount when toggling + triggerEvent(root.children[1] as TestElement, 'click') + await nextTick() + expect(serializeInner(root)).toBe(``) + expect(unmountSpy).toHaveBeenCalledTimes(1) + expect(mountSpy).toHaveBeenCalledTimes(1) + expect(activeSpy).toHaveBeenCalledTimes(1) + expect(deactiveSpy).toHaveBeenCalledTimes(1) + + // should not mount when toggling + triggerEvent(root.children[1] as TestElement, 'click') + await nextTick() + expect(serializeInner(root)).toBe(`
1
`) + expect(unmountSpy).toHaveBeenCalledTimes(1) + expect(mountSpy).toHaveBeenCalledTimes(1) + expect(activeSpy).toHaveBeenCalledTimes(2) + expect(deactiveSpy).toHaveBeenCalledTimes(1) + }) + test('reload class component', async () => { const root = nodeOps.createElement('div') const childId = 'test4-child' diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 9cb80b94ef0..5914665bb98 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -473,7 +473,10 @@ function emptyPlaceholder(vnode: VNode): VNode | undefined { function getKeepAliveChild(vnode: VNode): VNode | undefined { return isKeepAlive(vnode) - ? vnode.children + ? // #7121 avoid the result is expired during HMR + vnode.component + ? vnode.component.subTree + : vnode.children ? ((vnode.children as VNodeArrayChildren)[0] as VNode) : undefined : vnode From 40a74cb935f33c62a5487b3cbc3e11ad83886564 Mon Sep 17 00:00:00 2001 From: Rairn <958414905@qq.com> Date: Sat, 4 Feb 2023 15:20:28 +0800 Subject: [PATCH 2/3] chore: fix test --- packages/runtime-core/__tests__/hmr.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts index d7c54cdc27d..25ca1eaa40b 100644 --- a/packages/runtime-core/__tests__/hmr.spec.ts +++ b/packages/runtime-core/__tests__/hmr.spec.ts @@ -222,10 +222,10 @@ describe('hot module replacement', () => { test('reload KeepAlive slot in Transition', async () => { const root = nodeOps.createElement('div') const childId = 'test-transition-keep-alive-reload' - const unmountSpy = jest.fn() - const mountSpy = jest.fn() - const activeSpy = jest.fn() - const deactiveSpy = jest.fn() + const unmountSpy = vi.fn() + const mountSpy = vi.fn() + const activeSpy = vi.fn() + const deactiveSpy = vi.fn() const Child: ComponentOptions = { __hmrId: childId, From 5bbfba6ea1e78e83f3ce5323717006cdd9860413 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 9 Nov 2023 16:22:22 +0800 Subject: [PATCH 3/3] Update BaseTransition.ts --- packages/runtime-core/src/components/BaseTransition.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 5914665bb98..8711d7271c2 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -473,8 +473,9 @@ function emptyPlaceholder(vnode: VNode): VNode | undefined { function getKeepAliveChild(vnode: VNode): VNode | undefined { return isKeepAlive(vnode) - ? // #7121 avoid the result is expired during HMR - vnode.component + ? // #7121 ensure get the child component subtree in case + // it's been replaced during HMR + __DEV__ && vnode.component ? vnode.component.subTree : vnode.children ? ((vnode.children as VNodeArrayChildren)[0] as VNode)