Skip to content

Commit f0c9dff

Browse files
committed
chore: tweaks
1 parent 46cf6a6 commit f0c9dff

File tree

1 file changed

+126
-128
lines changed

1 file changed

+126
-128
lines changed

packages/runtime-vapor/src/components/KeepAlive.ts

Lines changed: 126 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
316314
type InnerBlockResult =
317315
| [VaporFragment, true]
318316
| [VaporComponentInstance, false]

0 commit comments

Comments
 (0)