]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: refactor
authordaiwei <daiwei521@126.com>
Wed, 9 Apr 2025 07:49:00 +0000 (15:49 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 9 Apr 2025 07:49:00 +0000 (15:49 +0800)
packages/runtime-core/src/components/KeepAlive.ts
packages/runtime-core/src/index.ts
packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts
packages/runtime-vapor/src/block.ts
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/components/KeepAlive.ts

index dc27e6e59d76bb44a68821f28cfde387027945ad..89b0e83d5633d5892deb24e38720914fa577092c 100644 (file)
@@ -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
index 0b0e58af1ab4bf1d035ebc8fad6d3ead3eced884..8d87d4812590a3702aeb00268d2589aa13dc7d3e 100644 (file)
@@ -564,7 +564,7 @@ export { getComponentName } from './component'
 /**
  * @internal
  */
-export { matches, isKeepAlive } from './components/KeepAlive'
+export { matches, isKeepAlive, resetShapeFlag } from './components/KeepAlive'
 /**
  * @internal
  */
index d7829ec90f3232a9ae261232ff8ffb537bacc32a..ea1ee8527a5bac21e0d0aea8f602175655022203 100644 (file)
@@ -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,
index b782afd38d35b66c9fed33675d4f4705efbceb3f..c93e94612a68a542fd8cfcc43bc34dc4c28002f1 100644 (file)
@@ -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
index e4fbf8aa7d411a1d134e384b11ddda616f37834a..26a1226477f155d203a7c5812b2a37fee6aca110 100644 (file)
@@ -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
   }
 
index a861c5372b43c5d73a7d181931d7ed2c883aba13..6b7192c6bd8bfe4b876404ae3e2819cde98a2fb0 100644 (file)
@@ -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<CacheKey, VaporComponentInstance>
 type Keys = Set<CacheKey>
 
-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) {