From: daiwei Date: Wed, 9 Apr 2025 07:49:00 +0000 (+0800) Subject: wip: refactor X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dccc47c2655013abe60983f8f29ee1a3bd36fbb1;p=thirdparty%2Fvuejs%2Fcore.git wip: refactor --- diff --git a/packages/runtime-core/src/components/KeepAlive.ts b/packages/runtime-core/src/components/KeepAlive.ts index dc27e6e59d..89b0e83d56 100644 --- a/packages/runtime-core/src/components/KeepAlive.ts +++ b/packages/runtime-core/src/components/KeepAlive.ts @@ -73,7 +73,7 @@ export interface KeepAliveContext extends ComponentRenderContext { deactivate: (vnode: VNode) => void } -export const isKeepAlive = (vnode: VNode): boolean => +export const isKeepAlive = (vnode: any): boolean => (vnode.type as any).__isKeepAlive const KeepAliveImpl: ComponentOptions = { @@ -478,7 +478,7 @@ function injectToKeepAliveRoot( }, target) } -function resetShapeFlag(vnode: VNode) { +export function resetShapeFlag(vnode: any): void { // bitwise operations to remove keep alive flags vnode.shapeFlag &= ~ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE vnode.shapeFlag &= ~ShapeFlags.COMPONENT_KEPT_ALIVE diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 0b0e58af1a..8d87d48125 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -564,7 +564,7 @@ export { getComponentName } from './component' /** * @internal */ -export { matches, isKeepAlive } from './components/KeepAlive' +export { matches, isKeepAlive, resetShapeFlag } from './components/KeepAlive' /** * @internal */ diff --git a/packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts b/packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts index d7829ec90f..ea1ee8527a 100644 --- a/packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts +++ b/packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts @@ -9,8 +9,8 @@ import { } from 'vue' import type { VaporComponent } from '../../src/component' import { makeRender } from '../_utils' +import { VaporKeepAliveImpl as VaporKeepAlive } from '../../src/components/KeepAlive' import { - VaporKeepAlive, child, createComponent, createDynamicComponent, @@ -144,7 +144,7 @@ describe('VaporKeepAlive', () => { const { mount } = define({ setup() { const setTemplateRef = createTemplateRefSetter() - const n4 = createComponent(VaporKeepAlive as any, null, { + const n4 = createComponent(VaporKeepAlive, null, { default: () => { const n0 = createDynamicComponent(() => views[viewRef.value]) as any setTemplateRef(n0, instanceRef) @@ -180,7 +180,7 @@ describe('VaporKeepAlive', () => { return createIf( () => toggle.value, () => - createComponent(VaporKeepAlive as any, null, { + createComponent(VaporKeepAlive, null, { default: () => createDynamicComponent(() => views[viewRef.value]), }), ) @@ -235,7 +235,7 @@ describe('VaporKeepAlive', () => { return createIf( () => toggle.value, () => - createComponent(VaporKeepAlive as any, null, { + createComponent(VaporKeepAlive, null, { default: () => createDynamicComponent(() => views[viewRef.value]), }), ) @@ -295,7 +295,7 @@ describe('VaporKeepAlive', () => { const toggle = ref(true) const { html } = define({ setup() { - return createComponent(VaporKeepAlive as any, null, { + return createComponent(VaporKeepAlive, null, { default() { return createIf( () => toggle.value, @@ -350,7 +350,7 @@ describe('VaporKeepAlive', () => { const toggle = ref(true) const { html } = define({ setup() { - return createComponent(VaporKeepAlive as any, null, { + return createComponent(VaporKeepAlive, null, { default() { return createIf( () => toggle.value, @@ -375,7 +375,7 @@ describe('VaporKeepAlive', () => { onActivated(() => oneHooks.activated()) onDeactivated(() => oneHooks.deactivated()) onUnmounted(() => oneHooks.unmounted()) - return createComponent(VaporKeepAlive as any, null, { + return createComponent(VaporKeepAlive, null, { default() { return createIf( () => toggle2.value, @@ -389,7 +389,7 @@ describe('VaporKeepAlive', () => { const toggle1 = ref(true) const { html } = define({ setup() { - return createComponent(VaporKeepAlive as any, null, { + return createComponent(VaporKeepAlive, null, { default() { return createIf( () => toggle1.value, diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts index b782afd38d..c93e94612a 100644 --- a/packages/runtime-vapor/src/block.ts +++ b/packages/runtime-vapor/src/block.ts @@ -1,6 +1,7 @@ import { isArray } from '@vue/shared' import { type VaporComponentInstance, + currentInstance, isVaporComponent, mountComponent, unmountComponent, @@ -8,6 +9,8 @@ import { import { createComment, createTextNode } from './dom/node' import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity' import { isHydrating } from './dom/hydration' +import { isKeepAlive } from 'vue' +import type { KeepAliveInstance } from './components/KeepAlive' export type Block = | Node @@ -50,8 +53,14 @@ export class DynamicFragment extends VaporFragment { pauseTracking() const parent = this.anchor.parentNode + const instance = currentInstance! // teardown previous branch if (this.scope) { + if (isKeepAlive(instance)) { + ;(instance as KeepAliveInstance).process( + this.nodes as VaporComponentInstance, + ) + } this.scope.stop() parent && remove(this.nodes, parent) } @@ -59,6 +68,11 @@ export class DynamicFragment extends VaporFragment { if (render) { this.scope = new EffectScope() this.nodes = this.scope.run(render) || [] + if (isKeepAlive(instance)) { + ;(instance as KeepAliveInstance).process( + this.nodes as VaporComponentInstance, + ) + } if (parent) insert(this.nodes, parent, this.anchor) } else { this.scope = undefined diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index e4fbf8aa7d..26a1226477 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -15,7 +15,6 @@ import { currentInstance, endMeasure, expose, - isKeepAlive, nextUid, popWarningContext, pushWarningContext, @@ -36,7 +35,13 @@ import { resetTracking, unref, } from '@vue/reactivity' -import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared' +import { + EMPTY_OBJ, + ShapeFlags, + invokeArrayFns, + isFunction, + isString, +} from '@vue/shared' import { type DynamicPropsSource, type RawProps, @@ -376,6 +381,7 @@ export class VaporComponentInstance implements GenericComponentInstance { propsOptions?: NormalizedPropsOptions emitsOptions?: ObjectEmitsOptions | null isSingleRoot?: boolean + shapeFlag?: number constructor( comp: VaporComponent, @@ -498,13 +504,12 @@ export function mountComponent( parentNode: ParentNode, anchor?: Node | null | 0, ): void { - let parent - if ( - (parent = instance.parent) && - isKeepAlive(parent as any) && - (parent as KeepAliveInstance).isKeptAlive(instance) - ) { - ;(parent as KeepAliveInstance).activate(instance, parentNode, anchor as any) + if (instance.shapeFlag! & ShapeFlags.COMPONENT_KEPT_ALIVE) { + ;(instance.parent as KeepAliveInstance).activate( + instance, + parentNode, + anchor as any, + ) instance.isMounted = true return } @@ -516,9 +521,7 @@ export function mountComponent( insert(instance.block, parentNode, anchor) if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!)) if ( - parent && - isKeepAlive(parent as any) && - (parent as KeepAliveInstance).shouldKeepAlive(instance) && + instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE && instance.a ) { queuePostFlushCb(instance.a!) @@ -533,13 +536,8 @@ export function unmountComponent( instance: VaporComponentInstance, parentNode?: ParentNode, ): void { - let parent - if ( - (parent = instance.parent) && - isKeepAlive(parent as any) && - (parent as KeepAliveInstance).shouldKeepAlive(instance) - ) { - ;(parent as KeepAliveInstance).deactivate(instance) + if (instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) { + ;(instance.parent as KeepAliveInstance).deactivate(instance) return } diff --git a/packages/runtime-vapor/src/components/KeepAlive.ts b/packages/runtime-vapor/src/components/KeepAlive.ts index a861c5372b..6b7192c6bd 100644 --- a/packages/runtime-vapor/src/components/KeepAlive.ts +++ b/packages/runtime-vapor/src/components/KeepAlive.ts @@ -3,25 +3,25 @@ import { currentInstance, devtoolsComponentAdded, getComponentName, - invalidateMount, - isKeepAlive, matches, onBeforeUnmount, onMounted, onUpdated, queuePostFlushCb, + resetShapeFlag, warn, watch, } from '@vue/runtime-dom' import { type Block, insert, isFragment, isValidBlock } from '../block' import { + type ObjectVaporComponent, type VaporComponent, type VaporComponentInstance, isVaporComponent, unmountComponent, } from '../component' import { defineVaporComponent } from '../apiDefineComponent' -import { invokeArrayFns, isArray } from '@vue/shared' +import { ShapeFlags, invokeArrayFns, isArray } from '@vue/shared' export interface KeepAliveInstance extends VaporComponentInstance { activate: ( @@ -30,15 +30,14 @@ export interface KeepAliveInstance extends VaporComponentInstance { anchor: Node, ) => void deactivate: (instance: VaporComponentInstance) => void - shouldKeepAlive: (instance: VaporComponentInstance) => boolean - isKeptAlive: (instance: VaporComponentInstance) => boolean + process: (instance: VaporComponentInstance) => void } type CacheKey = PropertyKey | VaporComponent type Cache = Map type Keys = Set -const VaporKeepAliveImpl = defineVaporComponent({ +export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ name: 'VaporKeepAlive', // @ts-expect-error __isKeepAlive: true, @@ -57,7 +56,6 @@ const VaporKeepAliveImpl = defineVaporComponent({ const keys: Keys = new Set() const storageContainer = document.createElement('div') let current: VaporComponentInstance | undefined - let isUnmounting = false if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { ;(keepAliveInstance as any).__v_cache = cache @@ -90,9 +88,10 @@ const VaporKeepAliveImpl = defineVaporComponent({ onMounted(cacheBlock) onUpdated(cacheBlock) + onBeforeUnmount(() => { - isUnmounting = true cache.forEach(cached => { + resetShapeFlag(cached) cache.delete(cached.type) // current instance will be unmounted as part of keep-alive's unmount if (current && current.type === cached.type) { @@ -104,12 +103,20 @@ const VaporKeepAliveImpl = defineVaporComponent({ }) }) - const children = slots.default() - if (isArray(children) && children.length > 1) { - if (__DEV__) { - warn(`KeepAlive should contain exactly one component child.`) + keepAliveInstance.process = (instance: VaporComponentInstance) => { + if (cache.has(instance.type)) { + instance.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE + } + + const name = getComponentName(instance.type) + if ( + !( + (include && (!name || !matches(include, name))) || + (exclude && name && matches(exclude, name)) + ) + ) { + instance.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE } - return children } keepAliveInstance.activate = ( @@ -117,9 +124,6 @@ const VaporKeepAliveImpl = defineVaporComponent({ parentNode: ParentNode, anchor: Node, ) => { - // invalidateMount(instance.m) - // invalidateMount(instance.a) - const cachedBlock = cache.get(instance.type)! insert((instance.block = cachedBlock.block), parentNode, anchor) queuePostFlushCb(() => { @@ -144,20 +148,12 @@ const VaporKeepAliveImpl = defineVaporComponent({ } } - keepAliveInstance.shouldKeepAlive = (instance: VaporComponentInstance) => { - if (isUnmounting) return false - const name = getComponentName(instance.type) - if ( - (include && (!name || !matches(include, name))) || - (exclude && name && matches(exclude, name)) - ) { - return false + const children = slots.default() + if (isArray(children) && children.length > 1) { + if (__DEV__) { + warn(`KeepAlive should contain exactly one component child.`) } - return true - } - - keepAliveInstance.isKeptAlive = (instance: VaporComponentInstance) => { - return cache.has(instance.type) + return children } function pruneCache(filter: (name: string) => boolean) {