From eeb6ab886a35050b46f2d30235de33e3a9d8b67e Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 14 Apr 2025 10:15:25 +0800 Subject: [PATCH] wip: vdom interop --- .../runtime-core/src/components/KeepAlive.ts | 151 +++++++++++------- packages/runtime-core/src/index.ts | 8 +- .../runtime-vapor/src/components/KeepAlive.ts | 34 ++-- packages/runtime-vapor/src/vdomInterop.ts | 21 ++- 4 files changed, 128 insertions(+), 86 deletions(-) diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index eaa10e359..0a88a3303 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -1,4 +1,5 @@ import { + type ComponentInternalInstance, type ComponentOptions, type ConcreteComponent, type GenericComponentInstance, @@ -46,7 +47,7 @@ import { setTransitionHooks } from './BaseTransition' import type { ComponentRenderContext } from '../componentPublicInstance' import { devtoolsComponentAdded } from '../devtools' import { isAsyncWrapper } from '../apiAsyncComponent' -import { isSuspense } from './Suspense' +import { type SuspenseBoundary, isSuspense } from './Suspense' import { LifecycleHooks } from '../enums' type MatchPattern = string | RegExp | (string | RegExp)[] @@ -118,14 +119,11 @@ const KeepAliveImpl: ComponentOptions = { const parentSuspense = keepAliveInstance.suspense + const { renderer } = sharedContext const { - renderer: { - p: patch, - m: move, - um: _unmount, - o: { createElement }, - }, - } = sharedContext + um: _unmount, + o: { createElement }, + } = renderer const storageContainer = createElement('div') sharedContext.activate = ( @@ -135,72 +133,26 @@ const KeepAliveImpl: ComponentOptions = { namespace, optimized, ) => { - const instance = vnode.component! - move( + activate( vnode, container, anchor, - MoveType.ENTER, + renderer, keepAliveInstance, parentSuspense, - ) - // in case props have changed - patch( - instance.vnode, - vnode, - container, - anchor, - instance, - parentSuspense, namespace, - vnode.slotScopeIds, optimized, ) - queuePostRenderEffect(() => { - instance.isDeactivated = false - if (instance.a) { - invokeArrayFns(instance.a) - } - const vnodeHook = vnode.props && vnode.props.onVnodeMounted - if (vnodeHook) { - invokeVNodeHook(vnodeHook, instance.parent, vnode) - } - }, parentSuspense) - - if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { - // Update components tree - devtoolsComponentAdded(instance) - } } sharedContext.deactivate = (vnode: VNode) => { - const instance = vnode.component! - invalidateMount(instance.m) - invalidateMount(instance.a) - - move( + deactivate( vnode, storageContainer, - null, - MoveType.LEAVE, + renderer, keepAliveInstance, parentSuspense, ) - queuePostRenderEffect(() => { - if (instance.da) { - invokeArrayFns(instance.da) - } - const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted - if (vnodeHook) { - invokeVNodeHook(vnodeHook, instance.parent, vnode) - } - instance.isDeactivated = true - }, parentSuspense) - - if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { - // Update components tree - devtoolsComponentAdded(instance) - } } function unmount(vnode: VNode) { @@ -487,3 +439,86 @@ export function resetShapeFlag(vnode: any): void { function getInnerChild(vnode: VNode) { return vnode.shapeFlag & ShapeFlags.SUSPENSE ? vnode.ssContent! : vnode } + +/** + * shared between runtime-core and runtime-vapor + */ +export function activate( + vnode: VNode, + container: RendererElement, + anchor: RendererNode | null, + { p: patch, m: move }: RendererInternals, + parentComponent: ComponentInternalInstance | null, + parentSuspense: SuspenseBoundary | null, + namespace?: ElementNamespace, + optimized?: boolean, +): void { + const instance = vnode.component! + move( + vnode, + container, + anchor, + MoveType.ENTER, + parentComponent, + parentSuspense, + ) + // in case props have changed + patch( + instance.vnode, + vnode, + container, + anchor, + instance, + parentSuspense, + namespace, + vnode.slotScopeIds, + optimized, + ) + queuePostRenderEffect(() => { + instance.isDeactivated = false + if (instance.a) { + invokeArrayFns(instance.a) + } + const vnodeHook = vnode.props && vnode.props.onVnodeMounted + if (vnodeHook) { + invokeVNodeHook(vnodeHook, instance.parent, vnode) + } + }, parentSuspense) + + if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { + // Update components tree + devtoolsComponentAdded(instance) + } +} + +/** + * shared between runtime-core and runtime-vapor + */ +export function deactivate( + vnode: VNode, + container: RendererElement, + { m: move }: RendererInternals, + parentComponent: ComponentInternalInstance | null, + parentSuspense: SuspenseBoundary | null, +): void { + const instance = vnode.component! + invalidateMount(instance.m) + invalidateMount(instance.a) + + move(vnode, container, null, MoveType.LEAVE, parentComponent, parentSuspense) + queuePostRenderEffect(() => { + if (instance.da) { + invokeArrayFns(instance.da) + } + const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted + if (vnodeHook) { + invokeVNodeHook(vnodeHook, instance.parent, vnode) + } + instance.isDeactivated = true + }, parentSuspense) + + if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { + // Update components tree + devtoolsComponentAdded(instance) + } +} diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 8d87d4812..057d1158e 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -564,7 +564,13 @@ export { getComponentName } from './component' /** * @internal */ -export { matches, isKeepAlive, resetShapeFlag } from './components/KeepAlive' +export { + matches, + isKeepAlive, + resetShapeFlag, + activate, + deactivate, +} from './components/KeepAlive' /** * @internal */ diff --git a/packages/runtime-vapor/src/components/KeepAlive.ts b/packages/runtime-vapor/src/components/KeepAlive.ts index 439f0f3ff..cafefb1f1 100644 --- a/packages/runtime-vapor/src/components/KeepAlive.ts +++ b/packages/runtime-vapor/src/components/KeepAlive.ts @@ -31,15 +31,16 @@ import { createElement } from '../dom/node' export interface KeepAliveInstance extends VaporComponentInstance { activate: ( - block: VaporComponentInstance | VaporFragment, + instance: VaporComponentInstance, parentNode: ParentNode, anchor?: Node | null | 0, ) => void - deactivate: (block: VaporComponentInstance | VaporFragment) => void + deactivate: (instance: VaporComponentInstance) => void process: (block: Block) => void getCachedComponent: ( comp: VaporComponent, ) => VaporComponentInstance | VaporFragment | undefined + getStorageContainer: () => ParentNode } type CacheKey = VaporComponent @@ -128,6 +129,7 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ }) }) + keepAliveInstance.getStorageContainer = () => storageContainer keepAliveInstance.getCachedComponent = comp => cache.get(comp) const process = (keepAliveInstance.process = block => { @@ -143,18 +145,9 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ } }) - keepAliveInstance.activate = (block, parentNode, anchor) => { - current = block - let instance - if (isVaporComponent(block)) { - instance = block - insert(block.block, parentNode, anchor) - } else { - // vdom interop - const comp = block.nodes as any - insert(comp.el, parentNode, anchor) - instance = comp.component - } + keepAliveInstance.activate = (instance, parentNode, anchor) => { + current = instance + insert(instance.block, parentNode, anchor) queuePostFlushCb(() => { instance.isDeactivated = false @@ -166,17 +159,8 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ } } - keepAliveInstance.deactivate = block => { - let instance - if (isVaporComponent(block)) { - instance = block - insert(block.block, storageContainer) - } else { - // vdom interop - const comp = block.nodes as any - insert(comp.el, storageContainer) - instance = comp.component - } + keepAliveInstance.deactivate = instance => { + insert(instance.block, storageContainer) queuePostFlushCb(() => { if (instance.da) invokeArrayFns(instance.da) diff --git a/packages/runtime-vapor/src/vdomInterop.ts b/packages/runtime-vapor/src/vdomInterop.ts index 145c81e12..753cc50dc 100644 --- a/packages/runtime-vapor/src/vdomInterop.ts +++ b/packages/runtime-vapor/src/vdomInterop.ts @@ -9,8 +9,10 @@ import { type Slots, type VNode, type VaporInteropInterface, + activate, createVNode, currentInstance, + deactivate, ensureRenderer, onScopeDispose, renderSlot, @@ -174,7 +176,13 @@ function createVDOMComponent( const parentInstance = currentInstance as VaporComponentInstance const unmount = (parentNode?: ParentNode) => { if (vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) { - ;(parentInstance as KeepAliveInstance).deactivate(frag) + deactivate( + vnode, + (parentInstance as KeepAliveInstance).getStorageContainer(), + internals, + parentInstance as any, + null, + ) return } internals.umt(vnode.component!, null, !!parentNode) @@ -182,7 +190,16 @@ function createVDOMComponent( frag.insert = (parentNode, anchor) => { if (vnode.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) { - ;(parentInstance as KeepAliveInstance).activate(frag, parentNode, anchor) + activate( + vnode, + parentNode, + anchor, + internals, + parentInstance as any, + null, + undefined, + false, + ) return } if (!isMounted) {