From 4f1836678aa870c6f2a9ef6075e021aca7a1c5b8 Mon Sep 17 00:00:00 2001 From: linzhe Date: Sun, 21 Jul 2024 18:54:39 +0800 Subject: [PATCH 1/9] fix(runtime-core): Teloport in keepalive should be cached --- .../runtime-core/src/components/KeepAlive.ts | 84 ++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index a2c8c2bf1a7..31c17f36395 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -136,6 +136,47 @@ const KeepAliveImpl: ComponentOptions = { ) => { const instance = vnode.component! move(vnode, container, anchor, MoveType.ENTER, parentSuspense) + function activateTeleport(vnode: VNode) { + if (vnode.shapeFlag & ShapeFlags.TELEPORT && isArray(vnode.children)) { + for (let i = 0; i < vnode.children.length; i++) { + const subVnode = vnode.children[i] as VNode + move( + subVnode, + vnode.target!, + vnode.targetAnchor, + MoveType.ENTER, + parentSuspense, + ) + } + } + if (vnode.component) { + const subTree = vnode.component.subTree + if ( + subTree.shapeFlag & ShapeFlags.TELEPORT && + isArray(subTree.children) + ) { + for (let i = 0; i < subTree.children.length; i++) { + const subVnode = subTree.children[i] as VNode + move( + subVnode, + subTree.target!, + subTree.targetAnchor, + MoveType.ENTER, + parentSuspense, + ) + } + } + if (isArray(subTree.children)) { + for (let i = 0; i < subTree.children.length; i++) { + const child = subTree.children[i] + if (child) { + activateTeleport(child as VNode) + } + } + } + } + } + activateTeleport(vnode) // in case props have changed patch( instance.vnode, @@ -169,8 +210,49 @@ const KeepAliveImpl: ComponentOptions = { const instance = vnode.component! invalidateMount(instance.m) invalidateMount(instance.a) - move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense) + function deactivateTeleport(vnode: VNode) { + if (vnode.shapeFlag & ShapeFlags.TELEPORT && isArray(vnode.children)) { + // + for (let i = 0; i < vnode.children.length; i++) { + const subVnode = vnode.children[i] as VNode + move( + subVnode, + storageContainer, + null, + MoveType.LEAVE, + parentSuspense, + ) + } + } + if (vnode.component) { + const subTree = vnode.component.subTree + if ( + subTree.shapeFlag & ShapeFlags.TELEPORT && + isArray(subTree.children) + ) { + for (let i = 0; i < subTree.children.length; i++) { + const subVnode = subTree.children[i] as VNode + move( + subVnode, + storageContainer, + null, + MoveType.LEAVE, + parentSuspense, + ) + } + } + if (isArray(subTree.children)) { + for (let i = 0; i < subTree.children.length; i++) { + const child = subTree.children[i] + if (child) { + deactivateTeleport(child as VNode) + } + } + } + } + } + deactivateTeleport(vnode) queuePostRenderEffect(() => { if (instance.da) { invokeArrayFns(instance.da) From b36dc4d8ecaabf0880acb015b2220db44142ccad Mon Sep 17 00:00:00 2001 From: linzhe Date: Sun, 21 Jul 2024 19:13:24 +0800 Subject: [PATCH 2/9] chore: update --- .../runtime-core/src/components/KeepAlive.ts | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 31c17f36395..6353cd1e7a1 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -151,21 +151,8 @@ const KeepAliveImpl: ComponentOptions = { } if (vnode.component) { const subTree = vnode.component.subTree - if ( - subTree.shapeFlag & ShapeFlags.TELEPORT && - isArray(subTree.children) - ) { - for (let i = 0; i < subTree.children.length; i++) { - const subVnode = subTree.children[i] as VNode - move( - subVnode, - subTree.target!, - subTree.targetAnchor, - MoveType.ENTER, - parentSuspense, - ) - } - } + activateTeleport(subTree) + if (isArray(subTree.children)) { for (let i = 0; i < subTree.children.length; i++) { const child = subTree.children[i] @@ -175,6 +162,16 @@ const KeepAliveImpl: ComponentOptions = { } } } + if (isArray(vnode.children)) { + if (isArray(vnode.children)) { + for (let i = 0; i < vnode.children.length; i++) { + const child = vnode.children[i] + if (child) { + activateTeleport(child as VNode) + } + } + } + } } activateTeleport(vnode) // in case props have changed @@ -227,21 +224,7 @@ const KeepAliveImpl: ComponentOptions = { } if (vnode.component) { const subTree = vnode.component.subTree - if ( - subTree.shapeFlag & ShapeFlags.TELEPORT && - isArray(subTree.children) - ) { - for (let i = 0; i < subTree.children.length; i++) { - const subVnode = subTree.children[i] as VNode - move( - subVnode, - storageContainer, - null, - MoveType.LEAVE, - parentSuspense, - ) - } - } + deactivateTeleport(subTree) if (isArray(subTree.children)) { for (let i = 0; i < subTree.children.length; i++) { const child = subTree.children[i] @@ -251,6 +234,16 @@ const KeepAliveImpl: ComponentOptions = { } } } + if (isArray(vnode.children)) { + if (isArray(vnode.children)) { + for (let i = 0; i < vnode.children.length; i++) { + const child = vnode.children[i] + if (child) { + deactivateTeleport(child as VNode) + } + } + } + } } deactivateTeleport(vnode) queuePostRenderEffect(() => { From 476bb2e7ba81e935d34ef48d3fdcffb15b0ddfd8 Mon Sep 17 00:00:00 2001 From: linzhe Date: Sun, 21 Jul 2024 20:38:16 +0800 Subject: [PATCH 3/9] chore: update test --- .../__tests__/components/KeepAlive.spec.ts | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index 6d3f6a9b8b6..8146a3cdbc7 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -4,6 +4,7 @@ import { type ComponentPublicInstance, KeepAlive, type Ref, + Teleport, type TestElement, cloneVNode, createApp, @@ -22,6 +23,7 @@ import { reactive, ref, render, + resolveDynamicComponent, serializeInner, shallowRef, } from '@vue/runtime-test' @@ -977,4 +979,59 @@ describe('KeepAlive', () => { expect(mountedB).toHaveBeenCalledTimes(1) expect(unmountedB).toHaveBeenCalledTimes(0) }) + + // #3648 + test('teloport in keepalive should be cached', async () => { + const activeComponent = shallowRef() + const App = { + name: 'App', + setup() { + const headerRef = ref() + const provided = reactive({ headerRef }) + provide('App', provided) + return () => { + const render = [h('div', { ref: headerRef })] + if (activeComponent.value) { + render.push( + // @ts-expect-error + h(KeepAlive, null, [ + resolveDynamicComponent(h(activeComponent.value)), + ]), + ) + } + return render + } + }, + } + const Comp1 = { + name: 'Comp1', + setup() { + const App = inject('App') as any + return () => h(Teleport, { to: App.headerRef }, ['xxx']) + }, + } + const Comp2 = { + name: 'Comp2', + setup() { + return () => h('div', null, 'Comp2') + }, + } + const root = nodeOps.createElement('div') + render(h(App), root) + activeComponent.value = Comp1 + await nextTick() + expect(serializeInner(root)).toMatchInlineSnapshot( + `"
xxx
"`, + ) + activeComponent.value = Comp2 + await nextTick() + expect(serializeInner(root)).toMatchInlineSnapshot( + `"
Comp2
"`, + ) + activeComponent.value = Comp1 + await nextTick() + expect(serializeInner(root)).toMatchInlineSnapshot( + `"
xxx
"`, + ) + }) }) From 9d41a99fb17db0ce1612046aadebea9331e0b248 Mon Sep 17 00:00:00 2001 From: linzhe Date: Sun, 21 Jul 2024 20:40:39 +0800 Subject: [PATCH 4/9] chore: update --- packages/runtime-core/src/components/KeepAlive.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 6353cd1e7a1..7d2e11f552c 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -210,7 +210,6 @@ const KeepAliveImpl: ComponentOptions = { move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense) function deactivateTeleport(vnode: VNode) { if (vnode.shapeFlag & ShapeFlags.TELEPORT && isArray(vnode.children)) { - // for (let i = 0; i < vnode.children.length; i++) { const subVnode = vnode.children[i] as VNode move( From 90f3079ad54525fc13a6b46780ab9fb04615e532 Mon Sep 17 00:00:00 2001 From: linzhe Date: Sun, 21 Jul 2024 20:48:40 +0800 Subject: [PATCH 5/9] chore: update --- .../runtime-core/src/components/KeepAlive.ts | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 7d2e11f552c..f37f9288ce0 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -152,7 +152,6 @@ const KeepAliveImpl: ComponentOptions = { if (vnode.component) { const subTree = vnode.component.subTree activateTeleport(subTree) - if (isArray(subTree.children)) { for (let i = 0; i < subTree.children.length; i++) { const child = subTree.children[i] @@ -163,12 +162,10 @@ const KeepAliveImpl: ComponentOptions = { } } if (isArray(vnode.children)) { - if (isArray(vnode.children)) { - for (let i = 0; i < vnode.children.length; i++) { - const child = vnode.children[i] - if (child) { - activateTeleport(child as VNode) - } + for (let i = 0; i < vnode.children.length; i++) { + const child = vnode.children[i] + if (child) { + activateTeleport(child as VNode) } } } @@ -234,12 +231,10 @@ const KeepAliveImpl: ComponentOptions = { } } if (isArray(vnode.children)) { - if (isArray(vnode.children)) { - for (let i = 0; i < vnode.children.length; i++) { - const child = vnode.children[i] - if (child) { - deactivateTeleport(child as VNode) - } + for (let i = 0; i < vnode.children.length; i++) { + const child = vnode.children[i] + if (child) { + deactivateTeleport(child as VNode) } } } From c1e4ea5981a89b627f06189b88079a0be4ed9792 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Mon, 22 Jul 2024 09:26:49 +0800 Subject: [PATCH 6/9] chore: update comment --- packages/runtime-core/__tests__/components/KeepAlive.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index 8146a3cdbc7..bb58b23ff40 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -980,7 +980,7 @@ describe('KeepAlive', () => { expect(unmountedB).toHaveBeenCalledTimes(0) }) - // #3648 + // #11410 test('teloport in keepalive should be cached', async () => { const activeComponent = shallowRef() const App = { From 601218c50b7cbfb58caa52a10e70dded73d60d92 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Mon, 22 Jul 2024 15:12:32 +0800 Subject: [PATCH 7/9] chore: update --- .../runtime-core/src/components/KeepAlive.ts | 117 +++++++----------- .../runtime-core/src/components/Teleport.ts | 29 ++++- 2 files changed, 75 insertions(+), 71 deletions(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index f37f9288ce0..5d319719b77 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -47,6 +47,7 @@ import { devtoolsComponentAdded } from '../devtools' import { isAsyncWrapper } from '../apiAsyncComponent' import { isSuspense } from './Suspense' import { LifecycleHooks } from '../enums' +import type { TeleportImpl } from './Teleport' type MatchPattern = string | RegExp | (string | RegExp)[] @@ -136,41 +137,14 @@ const KeepAliveImpl: ComponentOptions = { ) => { const instance = vnode.component! move(vnode, container, anchor, MoveType.ENTER, parentSuspense) - function activateTeleport(vnode: VNode) { - if (vnode.shapeFlag & ShapeFlags.TELEPORT && isArray(vnode.children)) { - for (let i = 0; i < vnode.children.length; i++) { - const subVnode = vnode.children[i] as VNode - move( - subVnode, - vnode.target!, - vnode.targetAnchor, - MoveType.ENTER, - parentSuspense, - ) - } - } - if (vnode.component) { - const subTree = vnode.component.subTree - activateTeleport(subTree) - if (isArray(subTree.children)) { - for (let i = 0; i < subTree.children.length; i++) { - const child = subTree.children[i] - if (child) { - activateTeleport(child as VNode) - } - } - } - } - if (isArray(vnode.children)) { - for (let i = 0; i < vnode.children.length; i++) { - const child = vnode.children[i] - if (child) { - activateTeleport(child as VNode) - } - } - } - } - activateTeleport(vnode) + processPotentialTeleport(vnode, potentialTeleportVnode => { + ;(potentialTeleportVnode.type as typeof TeleportImpl).activate( + potentialTeleportVnode, + potentialTeleportVnode.target!, + null, + sharedContext.renderer, + ) + }) // in case props have changed patch( instance.vnode, @@ -205,41 +179,15 @@ const KeepAliveImpl: ComponentOptions = { invalidateMount(instance.m) invalidateMount(instance.a) move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense) - function deactivateTeleport(vnode: VNode) { - if (vnode.shapeFlag & ShapeFlags.TELEPORT && isArray(vnode.children)) { - for (let i = 0; i < vnode.children.length; i++) { - const subVnode = vnode.children[i] as VNode - move( - subVnode, - storageContainer, - null, - MoveType.LEAVE, - parentSuspense, - ) - } - } - if (vnode.component) { - const subTree = vnode.component.subTree - deactivateTeleport(subTree) - if (isArray(subTree.children)) { - for (let i = 0; i < subTree.children.length; i++) { - const child = subTree.children[i] - if (child) { - deactivateTeleport(child as VNode) - } - } - } - } - if (isArray(vnode.children)) { - for (let i = 0; i < vnode.children.length; i++) { - const child = vnode.children[i] - if (child) { - deactivateTeleport(child as VNode) - } - } - } - } - deactivateTeleport(vnode) + + processPotentialTeleport(vnode, potentialTeleportVnode => { + ;(potentialTeleportVnode.type as typeof TeleportImpl).deactivate( + potentialTeleportVnode, + storageContainer, + null, + sharedContext.renderer, + ) + }) queuePostRenderEffect(() => { if (instance.da) { invokeArrayFns(instance.da) @@ -525,3 +473,32 @@ function resetShapeFlag(vnode: VNode) { function getInnerChild(vnode: VNode) { return vnode.shapeFlag & ShapeFlags.SUSPENSE ? vnode.ssContent! : vnode } + +function processPotentialTeleport( + vnode: VNode, + handle: (teleportVnode: VNode) => void, +) { + if (vnode.shapeFlag & ShapeFlags.TELEPORT) { + handle && handle(vnode) + } + if (vnode.component) { + const subTree = vnode.component.subTree + if (subTree.shapeFlag & ShapeFlags.TELEPORT) + processPotentialTeleport(subTree, handle) + else if (isArray(subTree.children)) { + for (let i = 0; i < subTree.children.length; i++) { + const child = subTree.children[i] + if (child) { + processPotentialTeleport(child as VNode, handle) + } + } + } + } else if (isArray(vnode.children)) { + for (let i = 0; i < vnode.children.length; i++) { + const child = vnode.children[i] + if (child) { + processPotentialTeleport(child as VNode, handle) + } + } + } +} diff --git a/packages/runtime-core/src/components/Teleport.ts b/packages/runtime-core/src/components/Teleport.ts index 65437300cff..47737e6c143 100644 --- a/packages/runtime-core/src/components/Teleport.ts +++ b/packages/runtime-core/src/components/Teleport.ts @@ -292,7 +292,34 @@ export const TeleportImpl = { } } }, - + activate: ( + vnode: VNode, + container: RendererElement, + parentAnchor: RendererNode | null, + internals: RendererInternals, + ) => { + moveTeleport( + vnode, + container, + parentAnchor, + internals, + TeleportMoveTypes.TOGGLE, + ) + }, + deactivate: ( + vnode: VNode, + container: RendererElement, + parentAnchor: RendererNode | null, + internals: RendererInternals, + ) => { + moveTeleport( + vnode, + container, + parentAnchor, + internals, + TeleportMoveTypes.TOGGLE, + ) + }, move: moveTeleport, hydrate: hydrateTeleport, } From 55f8cf55416a79b23e13d8289ceecb432238113d Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Mon, 22 Jul 2024 15:15:54 +0800 Subject: [PATCH 8/9] chore: update --- packages/runtime-core/src/components/KeepAlive.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index 5d319719b77..7dd42fbf16a 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -137,10 +137,10 @@ const KeepAliveImpl: ComponentOptions = { ) => { const instance = vnode.component! move(vnode, container, anchor, MoveType.ENTER, parentSuspense) - processPotentialTeleport(vnode, potentialTeleportVnode => { - ;(potentialTeleportVnode.type as typeof TeleportImpl).activate( - potentialTeleportVnode, - potentialTeleportVnode.target!, + processPotentialTeleport(vnode, teleportVnode => { + ;(teleportVnode.type as typeof TeleportImpl).activate( + teleportVnode, + teleportVnode.target!, null, sharedContext.renderer, ) @@ -180,9 +180,9 @@ const KeepAliveImpl: ComponentOptions = { invalidateMount(instance.a) move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense) - processPotentialTeleport(vnode, potentialTeleportVnode => { - ;(potentialTeleportVnode.type as typeof TeleportImpl).deactivate( - potentialTeleportVnode, + processPotentialTeleport(vnode, teleportVnode => { + ;(teleportVnode.type as typeof TeleportImpl).deactivate( + teleportVnode, storageContainer, null, sharedContext.renderer, From 88bb5a6166f6b85707cdbd90395b94756afb2ce3 Mon Sep 17 00:00:00 2001 From: linzhe141 <1572213544@qq.com> Date: Fri, 26 Jul 2024 16:35:43 +0800 Subject: [PATCH 9/9] chore: update --- packages/runtime-core/__tests__/components/KeepAlive.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts index bb58b23ff40..f6d17cc2a90 100644 --- a/packages/runtime-core/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-core/__tests__/components/KeepAlive.spec.ts @@ -981,7 +981,7 @@ describe('KeepAlive', () => { }) // #11410 - test('teloport in keepalive should be cached', async () => { + test('teleport in keepalive should be cached', async () => { const activeComponent = shallowRef() const App = { name: 'App',