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)