11import {
22 type GenericComponentInstance ,
33 type KeepAliveProps ,
4+ type VNode ,
45 currentInstance ,
56 devtoolsComponentAdded ,
67 getComponentName ,
@@ -25,7 +26,11 @@ import {
2526import { defineVaporComponent } from '../apiDefineComponent'
2627import { ShapeFlags , invokeArrayFns , isArray } from '@vue/shared'
2728import { createElement } from '../dom/node'
28- import { type VaporFragment , isFragment } from '../fragment'
29+ import {
30+ type DynamicFragment ,
31+ type VaporFragment ,
32+ isFragment ,
33+ } from '../fragment'
2934
3035export interface KeepAliveInstance extends VaporComponentInstance {
3136 activate : (
@@ -34,15 +39,16 @@ export interface KeepAliveInstance extends VaporComponentInstance {
3439 anchor ?: Node | null | 0 ,
3540 ) => void
3641 deactivate : ( instance : VaporComponentInstance ) => void
37- process : ( block : Block ) => void
3842 cacheComponent : ( instance : VaporComponentInstance ) => void
3943 getCachedComponent : (
4044 comp : VaporComponent ,
4145 ) => VaporComponentInstance | VaporFragment | undefined
4246 getStorageContainer : ( ) => ParentNode
47+ processFragment : ( fragment : DynamicFragment ) => void
48+ cacheFragment : ( fragment : DynamicFragment ) => void
4349}
4450
45- type CacheKey = VaporComponent
51+ type CacheKey = VaporComponent | VNode [ 'type' ]
4652type Cache = Map < CacheKey , VaporComponentInstance | VaporFragment >
4753type Keys = Set < CacheKey >
4854
@@ -116,54 +122,55 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
116122 const innerBlock = getInnerBlock ( block ) !
117123 if ( ! innerBlock || ! shouldCache ( innerBlock ) ) return
118124
119- const key = innerBlock . type
120- const blockToCache =
121- isFragment ( block ) && isVdomInteropFragment ( block . nodes )
122- ? // cache the fragment nodes for vdom interop
123- block . nodes
124- : isVdomInteropFragment ( block )
125- ? block
126- : innerBlock
127-
128- innerCacheBlock ( key , blockToCache )
125+ let toCache : VaporComponentInstance | VaporFragment
126+ let key : CacheKey
127+ let frag : VaporFragment | undefined
128+ if ( isFragment ( block ) && ( frag = findInteropFragment ( block ) ) ) {
129+ // vdom component: cache the fragment
130+ toCache = frag
131+ key = getCacheKey ( frag )
132+ } else {
133+ // vapor component: cache the instance
134+ toCache = innerBlock
135+ key = innerBlock . type
136+ }
137+ innerCacheBlock ( key , toCache )
129138 }
130139
131140 onMounted ( cacheBlock )
132141 onUpdated ( cacheBlock )
133142
134143 onBeforeUnmount ( ( ) => {
135- cache . forEach ( item => {
136- const cached = getInnerComponent ( item ) !
137- resetShapeFlag ( cached )
138- cache . delete ( cached . type )
144+ cache . forEach ( ( cached , key ) => {
145+ const instance = getInstanceFromCache ( cached )
146+ if ( ! instance ) return
147+
148+ resetCachedShapeFlag ( cached )
149+ cache . delete ( key )
150+
139151 // current instance will be unmounted as part of keep-alive's unmount
140152 if ( current ) {
141- const innerComp = getInnerComponent ( current ) !
142- if ( innerComp . type === cached . type ) {
143- const instance = cached . vapor
144- ? cached
145- : // vdom interop
146- ( cached as any ) . component
153+ const currentKey = getCacheKey ( current )
154+ if ( currentKey === key ) {
155+ // call deactivated hook
147156 const da = instance . da
148157 da && queuePostFlushCb ( da )
149158 return
150159 }
151160 }
152- remove ( item , storageContainer )
161+
162+ remove ( cached , storageContainer )
153163 } )
154164 } )
155165
156166 keepAliveInstance . getStorageContainer = ( ) => storageContainer
167+
157168 keepAliveInstance . getCachedComponent = comp => {
158169 // For async components, use the resolved component type as the cache key
159- const key = ( comp as any ) . __asyncResolved || comp
160- return cache . get ( key )
170+ return cache . get ( comp . __asyncResolved || comp )
161171 }
162172
163- const processShapeFlag = ( keepAliveInstance . process = block => {
164- const instance = getInnerComponent ( block )
165- if ( ! instance ) return
166-
173+ const setShapeFlags = ( instance : VaporComponentInstance ) => {
167174 // For unresolved async wrappers, skip processing
168175 // Wait for resolution and re-process via createInnerComp
169176 if ( isAsyncWrapper ( instance ) && ! instance . type . __asyncResolved ) {
@@ -177,14 +184,51 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
177184 if ( shouldCache ( instance ) ) {
178185 instance . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
179186 }
180- } )
187+ }
181188
182189 keepAliveInstance . cacheComponent = ( instance : VaporComponentInstance ) => {
183190 if ( ! shouldCache ( instance ) ) return
184- processShapeFlag ( instance )
191+ setShapeFlags ( instance )
185192 innerCacheBlock ( instance . type , instance )
186193 }
187194
195+ keepAliveInstance . processFragment = ( frag : DynamicFragment ) => {
196+ const innerBlock = getInnerBlock ( frag . nodes )
197+ if ( ! innerBlock ) return
198+
199+ const fragment = findInteropFragment ( frag . nodes )
200+ if ( fragment ) {
201+ setVdomShapeFlags ( fragment )
202+ } else {
203+ setShapeFlags ( innerBlock )
204+ }
205+ }
206+
207+ keepAliveInstance . cacheFragment = ( fragment : DynamicFragment ) => {
208+ // Find the component within the fragment
209+ const innerBlock = getInnerBlock ( fragment . nodes )
210+ if ( ! innerBlock || ! shouldCache ( innerBlock ) ) return
211+
212+ // Determine what to cache based on fragment type
213+ let toCache : VaporComponentInstance | VaporFragment
214+ let key : CacheKey
215+
216+ // find vdom interop fragment
217+ const frag = findInteropFragment ( fragment )
218+ if ( frag ) {
219+ // For vdom components, set shapeFlag
220+ setVdomShapeFlags ( frag )
221+ toCache = frag
222+ key = getCacheKey ( frag ) !
223+ } else {
224+ setShapeFlags ( innerBlock )
225+ toCache = innerBlock
226+ key = innerBlock . type
227+ }
228+
229+ innerCacheBlock ( key , toCache )
230+ }
231+
188232 keepAliveInstance . activate = ( instance , parentNode , anchor ) => {
189233 current = instance
190234 activate ( instance , parentNode , anchor )
@@ -194,6 +238,34 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
194238 deactivate ( instance , storageContainer )
195239 }
196240
241+ function setVdomShapeFlags (
242+ fragment : VaporFragment ,
243+ shouldKeepAlive : boolean = true ,
244+ ) {
245+ if ( shouldKeepAlive ) {
246+ fragment . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
247+ }
248+ const fragKey = getCacheKey ( fragment )
249+ if ( fragKey && cache . has ( fragKey ) ) {
250+ fragment . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_KEPT_ALIVE
251+ }
252+ // Also set shapeFlag on the component instance if it exists
253+ const vnode = fragment . vnode as any
254+ if ( vnode && vnode . component ) {
255+ vnode . component . shapeFlag = fragment . vnode ! . shapeFlag
256+ }
257+ }
258+
259+ function resetCachedShapeFlag (
260+ cached : VaporComponentInstance | VaporFragment ,
261+ ) {
262+ if ( isVaporComponent ( cached ) ) {
263+ resetShapeFlag ( cached )
264+ } else {
265+ resetShapeFlag ( cached . vnode )
266+ }
267+ }
268+
197269 let children = slots . default ( )
198270 if ( isArray ( children ) && children . length > 1 ) {
199271 if ( __DEV__ ) {
@@ -202,18 +274,18 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
202274 return children
203275 }
204276
205- // `children` could be either a `VaporComponentInstance` or a `DynamicFragment`
206- // (when using `v-if` or `<component is/>`). For `DynamicFragment` children,
207- // the `shapeFlag` is processed in `DynamicFragment.update`. Here only need
208- // to process the `VaporComponentInstance`
209- if ( isVaporComponent ( children ) ) processShapeFlag ( children )
210- else if ( isVdomInteropFragment ( children ) ) {
211- children . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
277+ // Process shapeFlag for vapor and vdom components
278+ // DynamicFragment (v-if, <component is/>) is processed in DynamicFragment.update
279+ if ( isVaporComponent ( children ) ) {
280+ setShapeFlags ( children )
281+ } else if ( isInteropFragment ( children ) ) {
282+ setVdomShapeFlags ( children , true )
212283 }
213284
214285 function pruneCache ( filter : ( name : string ) => boolean ) {
215- cache . forEach ( ( instance , key ) => {
216- instance = getInnerComponent ( instance ) !
286+ cache . forEach ( ( cached , key ) => {
287+ const instance = getInstanceFromCache ( cached )
288+ if ( ! instance ) return
217289 const name = getComponentName ( instance . type )
218290 if ( name && ! filter ( name ) ) {
219291 pruneCacheEntry ( key )
@@ -223,7 +295,9 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
223295
224296 function pruneCacheEntry ( key : CacheKey ) {
225297 const cached = cache . get ( key ) !
226- resetShapeFlag ( cached )
298+
299+ resetCachedShapeFlag ( cached )
300+
227301 // don't unmount if the instance is the current one
228302 if ( cached !== current ) {
229303 remove ( cached )
@@ -251,25 +325,44 @@ function getInnerBlock(block: Block): VaporComponentInstance | undefined {
251325 if ( isVaporComponent ( block ) ) {
252326 return block
253327 }
254- if ( isVdomInteropFragment ( block ) ) {
328+ if ( isInteropFragment ( block ) ) {
255329 return block . vnode as any
256330 }
257331 if ( isFragment ( block ) ) {
258332 return getInnerBlock ( block . nodes )
259333 }
260334}
261335
262- function getInnerComponent ( block : Block ) : VaporComponentInstance | undefined {
263- if ( isVaporComponent ( block ) ) {
336+ function isInteropFragment ( block : Block ) : block is VaporFragment {
337+ return ! ! ( isFragment ( block ) && block . vnode )
338+ }
339+
340+ function findInteropFragment ( block : Block ) : VaporFragment | undefined {
341+ if ( isInteropFragment ( block ) ) {
264342 return block
265- } else if ( ( block as any as GenericComponentInstance ) . vnode ) {
266- // vdom interop
267- return ( block as any as GenericComponentInstance ) . vnode as any
343+ }
344+ if ( isFragment ( block ) ) {
345+ return findInteropFragment ( block . nodes )
268346 }
269347}
270348
271- function isVdomInteropFragment ( block : Block ) : block is VaporFragment {
272- return ! ! ( isFragment ( block ) && block . insert )
349+ function getInstanceFromCache (
350+ cached : VaporComponentInstance | VaporFragment ,
351+ ) : GenericComponentInstance {
352+ if ( isVaporComponent ( cached ) ) {
353+ return cached
354+ }
355+ // vdom interop
356+ return cached . vnode ! . component as GenericComponentInstance
357+ }
358+
359+ function getCacheKey ( block : VaporComponentInstance | VaporFragment ) : CacheKey {
360+ if ( isVaporComponent ( block ) ) {
361+ return block . type
362+ }
363+
364+ // vdom interop
365+ return block . vnode ! . type
273366}
274367
275368export function activate (
0 commit comments