@@ -78,36 +78,32 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
7878 ; ( keepAliveInstance as any ) . __v_cache = cache
7979 }
8080
81- function shouldCache (
82- block : GenericComponentInstance | VaporFragment ,
83- interop : boolean = false ,
84- ) {
85- const isAsync =
86- ! interop && isAsyncWrapper ( block as GenericComponentInstance )
87- const type = (
88- interop
89- ? ( block as VaporFragment ) . vnode ! . type
90- : ( block as GenericComponentInstance ) . type
91- ) as GenericComponent & AsyncComponentInternalOptions
92-
93- // For unresolved async wrappers, skip caching
94- // Wait for resolution and re-process in createInnerComp
95- if ( isAsync && ! type . __asyncResolved ) {
96- return false
81+ keepAliveInstance . getStorageContainer = ( ) => storageContainer
82+
83+ keepAliveInstance . getCachedComponent = comp => cache . get ( comp )
84+
85+ keepAliveInstance . cacheComponent = ( instance : VaporComponentInstance ) => {
86+ if ( ! shouldCache ( instance as GenericComponentInstance , props ) ) {
87+ return
9788 }
89+ instance . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
90+ innerCacheBlock ( instance . type , instance )
91+ }
9892
99- const { include, exclude } = props
100- const name = getComponentName ( isAsync ? type . __asyncResolved ! : type )
101- return ! (
102- ( include && ( ! name || ! matches ( include , name ) ) ) ||
103- ( exclude && name && matches ( exclude , name ) )
104- )
93+ keepAliveInstance . activate = ( instance , parentNode , anchor ) => {
94+ current = instance
95+ activate ( instance , parentNode , anchor )
96+ }
97+
98+ keepAliveInstance . deactivate = instance => {
99+ current = undefined
100+ deactivate ( instance , storageContainer )
105101 }
106102
107- function innerCacheBlock (
103+ const innerCacheBlock = (
108104 key : CacheKey ,
109105 instance : VaporComponentInstance | VaporFragment ,
110- ) {
106+ ) => {
111107 const { max } = props
112108
113109 if ( cache . has ( key ) ) {
@@ -126,119 +122,117 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
126122 current = instance
127123 }
128124
129- function cacheBlock ( ) {
125+ const cacheBlock = ( ) => {
130126 // TODO suspense
131127 const block = keepAliveInstance . block !
132128 const [ innerBlock , interop ] = getInnerBlock ( block ) !
133- if ( ! innerBlock || ! shouldCache ( innerBlock , interop ) ) return
129+ if ( ! innerBlock || ! shouldCache ( innerBlock , props , interop ) ) return
134130 innerCacheBlock (
135131 interop ? innerBlock . vnode ! . type : innerBlock . type ,
136132 innerBlock ,
137133 )
138134 }
139135
140- onMounted ( cacheBlock )
141- onUpdated ( cacheBlock )
142-
143- onBeforeUnmount ( ( ) => {
144- cache . forEach ( ( cached , key ) => {
145- const instance = getInstanceFromCache ( cached )
146- if ( ! instance ) return
147-
148- resetCachedShapeFlag ( cached )
149- cache . delete ( key )
150-
151- // current instance will be unmounted as part of keep-alive's unmount
152- if ( current ) {
153- const currentKey = isVaporComponent ( current )
154- ? current . type
155- : current . vnode ! . type
156- if ( currentKey === key ) {
157- // call deactivated hook
158- const da = instance . da
159- da && queuePostFlushCb ( da )
160- return
161- }
162- }
163-
164- remove ( cached , storageContainer )
165- } )
166- keptAliveScopes . forEach ( scope => scope . stop ( ) )
167- keptAliveScopes . clear ( )
168- } )
169-
170- keepAliveInstance . getStorageContainer = ( ) => storageContainer
171-
172- keepAliveInstance . getCachedComponent = comp => cache . get ( comp )
173-
174- keepAliveInstance . cacheComponent = ( instance : VaporComponentInstance ) => {
175- if ( ! shouldCache ( instance as GenericComponentInstance ) ) return
176- instance . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
177- innerCacheBlock ( instance . type , instance )
178- }
179-
180136 const processFragment = ( frag : DynamicFragment ) => {
181137 const [ innerBlock , interop ] = getInnerBlock ( frag . nodes )
182- if ( ! innerBlock && ! shouldCache ( innerBlock ! , interop ) ) return
138+ if ( ! innerBlock && ! shouldCache ( innerBlock ! , props , interop ) ) return
183139
184140 if ( interop ) {
185141 if ( cache . has ( innerBlock . vnode ! . type ) ) {
186142 innerBlock . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_KEPT_ALIVE
187143 }
188- if ( shouldCache ( innerBlock ! , true ) ) {
144+ if ( shouldCache ( innerBlock ! , props , true ) ) {
189145 innerBlock . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
190146 }
191147 } else {
192148 if ( cache . has ( innerBlock ! . type ) ) {
193149 innerBlock ! . shapeFlag ! |= ShapeFlags . COMPONENT_KEPT_ALIVE
194150 }
195- if ( shouldCache ( innerBlock ! ) ) {
151+ if ( shouldCache ( innerBlock ! , props ) ) {
196152 innerBlock ! . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
197153 }
198154 }
199155 }
200156
201157 const cacheFragment = ( fragment : DynamicFragment ) => {
202158 const [ innerBlock , interop ] = getInnerBlock ( fragment . nodes )
203- if ( ! innerBlock || ! shouldCache ( innerBlock , interop ) ) return
159+ if ( ! innerBlock || ! shouldCache ( innerBlock , props , interop ) ) return
204160
205- // Determine what to cache based on fragment type
206- let toCache : VaporComponentInstance | VaporFragment
207161 let key : CacheKey
208-
209162 if ( interop ) {
210163 innerBlock . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
211- toCache = innerBlock
212164 key = innerBlock . vnode ! . type
213165 } else {
214166 innerBlock . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
215- toCache = innerBlock
216167 key = innerBlock . type
217168 }
218-
219- innerCacheBlock ( key , toCache )
169+ innerCacheBlock ( key , innerBlock )
220170 }
221171
222- keepAliveInstance . activate = ( instance , parentNode , anchor ) => {
223- current = instance
224- activate ( instance , parentNode , anchor )
172+ const pruneCache = ( filter : ( name : string ) => boolean ) => {
173+ cache . forEach ( ( cached , key ) => {
174+ const instance = getInstanceFromCache ( cached )
175+ if ( ! instance ) return
176+ const name = getComponentName ( instance . type )
177+ if ( name && ! filter ( name ) ) {
178+ pruneCacheEntry ( key )
179+ }
180+ } )
225181 }
226182
227- keepAliveInstance . deactivate = instance => {
228- current = undefined
229- deactivate ( instance , storageContainer )
230- }
183+ const pruneCacheEntry = ( key : CacheKey ) => {
184+ const cached = cache . get ( key ) !
231185
232- function resetCachedShapeFlag (
233- cached : VaporComponentInstance | VaporFragment ,
234- ) {
235- if ( isVaporComponent ( cached ) ) {
236- resetShapeFlag ( cached )
237- } else {
238- resetShapeFlag ( cached . vnode )
186+ resetCachedShapeFlag ( cached )
187+
188+ // don't unmount if the instance is the current one
189+ if ( cached !== current ) {
190+ remove ( cached )
239191 }
192+ cache . delete ( key )
193+ keys . delete ( key )
240194 }
241195
196+ // prune cache on include/exclude prop change
197+ watch (
198+ ( ) => [ props . include , props . exclude ] ,
199+ ( [ include , exclude ] ) => {
200+ include && pruneCache ( name => matches ( include , name ) )
201+ exclude && pruneCache ( name => ! matches ( exclude , name ) )
202+ } ,
203+ // prune post-render after `current` has been updated
204+ { flush : 'post' , deep : true } ,
205+ )
206+
207+ onMounted ( cacheBlock )
208+ onUpdated ( cacheBlock )
209+ onBeforeUnmount ( ( ) => {
210+ cache . forEach ( ( cached , key ) => {
211+ const instance = getInstanceFromCache ( cached )
212+ if ( ! instance ) return
213+
214+ resetCachedShapeFlag ( cached )
215+ cache . delete ( key )
216+
217+ // current instance will be unmounted as part of keep-alive's unmount
218+ if ( current ) {
219+ const currentKey = isVaporComponent ( current )
220+ ? current . type
221+ : current . vnode ! . type
222+ if ( currentKey === key ) {
223+ // call deactivated hook
224+ const da = instance . da
225+ da && queuePostFlushCb ( da )
226+ return
227+ }
228+ }
229+
230+ remove ( cached , storageContainer )
231+ } )
232+ keptAliveScopes . forEach ( scope => scope . stop ( ) )
233+ keptAliveScopes . clear ( )
234+ } )
235+
242236 let children = slots . default ( )
243237 if ( isArray ( children ) && children . length > 1 ) {
244238 if ( __DEV__ ) {
@@ -253,6 +247,9 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
253247 } else if ( isInteropFragment ( children ) ) {
254248 children . vnode ! . shapeFlag ! |= ShapeFlags . COMPONENT_SHOULD_KEEP_ALIVE
255249 } else if ( isDynamicFragment ( children ) ) {
250+ processFragment ( children )
251+
252+ // re-process fragment when fragment updates
256253 ; ( children . beforeTeardown || ( children . beforeTeardown = [ ] ) ) . push (
257254 ( oldKey , nodes , scope ) => {
258255 processFragment ( children )
@@ -263,56 +260,57 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
263260 ; ( children . beforeMount || ( children . beforeMount = [ ] ) ) . push ( ( ) =>
264261 cacheFragment ( children ) ,
265262 )
263+
264+ // get scope for fragment
266265 children . getScope = key => {
267266 const scope = keptAliveScopes . get ( key )
268267 if ( scope ) {
269268 keptAliveScopes . delete ( key )
270269 return scope
271270 }
272271 }
273-
274- processFragment ( children )
275- }
276-
277- function pruneCache ( filter : ( name : string ) => boolean ) {
278- cache . forEach ( ( cached , key ) => {
279- const instance = getInstanceFromCache ( cached )
280- if ( ! instance ) return
281- const name = getComponentName ( instance . type )
282- if ( name && ! filter ( name ) ) {
283- pruneCacheEntry ( key )
284- }
285- } )
286- }
287-
288- function pruneCacheEntry ( key : CacheKey ) {
289- const cached = cache . get ( key ) !
290-
291- resetCachedShapeFlag ( cached )
292-
293- // don't unmount if the instance is the current one
294- if ( cached !== current ) {
295- remove ( cached )
296- }
297- cache . delete ( key )
298- keys . delete ( key )
299272 }
300273
301- // prune cache on include/exclude prop change
302- watch (
303- ( ) => [ props . include , props . exclude ] ,
304- ( [ include , exclude ] ) => {
305- include && pruneCache ( name => matches ( include , name ) )
306- exclude && pruneCache ( name => ! matches ( exclude , name ) )
307- } ,
308- // prune post-render after `current` has been updated
309- { flush : 'post' , deep : true } ,
310- )
311-
312274 return children
313275 } ,
314276} )
315277
278+ const shouldCache = (
279+ block : GenericComponentInstance | VaporFragment ,
280+ props : KeepAliveProps ,
281+ interop : boolean = false ,
282+ ) => {
283+ const isAsync = ! interop && isAsyncWrapper ( block as GenericComponentInstance )
284+ const type = (
285+ interop
286+ ? ( block as VaporFragment ) . vnode ! . type
287+ : ( block as GenericComponentInstance ) . type
288+ ) as GenericComponent & AsyncComponentInternalOptions
289+
290+ // For unresolved async wrappers, skip caching
291+ // Wait for resolution and re-process in createInnerComp
292+ if ( isAsync && ! type . __asyncResolved ) {
293+ return false
294+ }
295+
296+ const { include, exclude } = props
297+ const name = getComponentName ( isAsync ? type . __asyncResolved ! : type )
298+ return ! (
299+ ( include && ( ! name || ! matches ( include , name ) ) ) ||
300+ ( exclude && name && matches ( exclude , name ) )
301+ )
302+ }
303+
304+ const resetCachedShapeFlag = (
305+ cached : VaporComponentInstance | VaporFragment ,
306+ ) => {
307+ if ( isVaporComponent ( cached ) ) {
308+ resetShapeFlag ( cached )
309+ } else {
310+ resetShapeFlag ( cached . vnode )
311+ }
312+ }
313+
316314type InnerBlockResult =
317315 | [ VaporFragment , true ]
318316 | [ VaporComponentInstance , false ]
0 commit comments