|
1 | 1 | import { |
| 2 | + type AsyncComponentInternalOptions, |
| 3 | + type GenericComponent, |
2 | 4 | type GenericComponentInstance, |
3 | 5 | type KeepAliveProps, |
4 | 6 | type VNode, |
@@ -76,19 +78,26 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ |
76 | 78 | ;(keepAliveInstance as any).__v_cache = cache |
77 | 79 | } |
78 | 80 |
|
79 | | - function shouldCache(instance: VaporComponentInstance) { |
| 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 | + |
80 | 93 | // For unresolved async wrappers, skip caching |
81 | 94 | // Wait for resolution and re-process in createInnerComp |
82 | | - if (isAsyncWrapper(instance) && !instance.type.__asyncResolved) { |
| 95 | + if (isAsync && !type.__asyncResolved) { |
83 | 96 | return false |
84 | 97 | } |
85 | 98 |
|
86 | 99 | const { include, exclude } = props |
87 | | - const name = getComponentName( |
88 | | - isAsyncWrapper(instance) |
89 | | - ? instance.type.__asyncResolved! |
90 | | - : instance.type, |
91 | | - ) |
| 100 | + const name = getComponentName(isAsync ? type.__asyncResolved! : type) |
92 | 101 | return !( |
93 | 102 | (include && (!name || !matches(include, name))) || |
94 | 103 | (exclude && name && matches(exclude, name)) |
@@ -120,22 +129,12 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ |
120 | 129 | function cacheBlock() { |
121 | 130 | // TODO suspense |
122 | 131 | const block = keepAliveInstance.block! |
123 | | - const innerBlock = getInnerBlock(block)! |
124 | | - if (!innerBlock || !shouldCache(innerBlock)) return |
125 | | - |
126 | | - let toCache: VaporComponentInstance | VaporFragment |
127 | | - let key: CacheKey |
128 | | - let frag: VaporFragment | undefined |
129 | | - if (isFragment(block) && (frag = findInteropFragment(block))) { |
130 | | - // vdom component: cache the fragment |
131 | | - toCache = frag |
132 | | - key = frag.vnode!.type |
133 | | - } else { |
134 | | - // vapor component: cache the instance |
135 | | - toCache = innerBlock |
136 | | - key = innerBlock.type |
137 | | - } |
138 | | - innerCacheBlock(key, toCache) |
| 132 | + const [innerBlock, interop] = getInnerBlock(block)! |
| 133 | + if (!innerBlock || !shouldCache(innerBlock, interop)) return |
| 134 | + innerCacheBlock( |
| 135 | + interop ? innerBlock.vnode!.type : innerBlock.type, |
| 136 | + innerBlock, |
| 137 | + ) |
139 | 138 | } |
140 | 139 |
|
141 | 140 | onMounted(cacheBlock) |
@@ -170,52 +169,47 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ |
170 | 169 |
|
171 | 170 | keepAliveInstance.getStorageContainer = () => storageContainer |
172 | 171 |
|
173 | | - keepAliveInstance.getCachedComponent = comp => { |
174 | | - return cache.get(comp) |
175 | | - } |
| 172 | + keepAliveInstance.getCachedComponent = comp => cache.get(comp) |
176 | 173 |
|
177 | 174 | keepAliveInstance.cacheComponent = (instance: VaporComponentInstance) => { |
178 | | - if (!shouldCache(instance)) return |
| 175 | + if (!shouldCache(instance as GenericComponentInstance)) return |
179 | 176 | instance.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
180 | 177 | innerCacheBlock(instance.type, instance) |
181 | 178 | } |
182 | 179 |
|
183 | 180 | const processFragment = (frag: DynamicFragment) => { |
184 | | - const innerBlock = getInnerBlock(frag.nodes) |
185 | | - if (!innerBlock) return |
| 181 | + const [innerBlock, interop] = getInnerBlock(frag.nodes) |
| 182 | + if (!innerBlock && !shouldCache(innerBlock!, interop)) return |
186 | 183 |
|
187 | | - const fragment = findInteropFragment(frag.nodes) |
188 | | - if (fragment) { |
189 | | - if (cache.has(fragment.vnode!.type)) { |
190 | | - fragment.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE |
| 184 | + if (interop) { |
| 185 | + if (cache.has(innerBlock.vnode!.type)) { |
| 186 | + innerBlock.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE |
191 | 187 | } |
192 | | - if (shouldCache(innerBlock)) { |
193 | | - fragment.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
| 188 | + if (shouldCache(innerBlock!, true)) { |
| 189 | + innerBlock.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
194 | 190 | } |
195 | 191 | } else { |
196 | | - if (cache.has(innerBlock.type)) { |
197 | | - innerBlock.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE |
| 192 | + if (cache.has(innerBlock!.type)) { |
| 193 | + innerBlock!.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE |
198 | 194 | } |
199 | | - if (shouldCache(innerBlock)) { |
200 | | - innerBlock.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
| 195 | + if (shouldCache(innerBlock!)) { |
| 196 | + innerBlock!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
201 | 197 | } |
202 | 198 | } |
203 | 199 | } |
204 | 200 |
|
205 | 201 | const cacheFragment = (fragment: DynamicFragment) => { |
206 | | - const innerBlock = getInnerBlock(fragment.nodes) |
207 | | - if (!innerBlock || !shouldCache(innerBlock)) return |
| 202 | + const [innerBlock, interop] = getInnerBlock(fragment.nodes) |
| 203 | + if (!innerBlock || !shouldCache(innerBlock, interop)) return |
208 | 204 |
|
209 | 205 | // Determine what to cache based on fragment type |
210 | 206 | let toCache: VaporComponentInstance | VaporFragment |
211 | 207 | let key: CacheKey |
212 | 208 |
|
213 | | - // find vdom interop fragment |
214 | | - const frag = findInteropFragment(fragment.nodes) |
215 | | - if (frag) { |
216 | | - frag.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
217 | | - toCache = frag |
218 | | - key = frag.vnode!.type |
| 209 | + if (interop) { |
| 210 | + innerBlock.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
| 211 | + toCache = innerBlock |
| 212 | + key = innerBlock.vnode!.type |
219 | 213 | } else { |
220 | 214 | innerBlock.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
221 | 215 | toCache = innerBlock |
@@ -253,33 +247,31 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ |
253 | 247 | return children |
254 | 248 | } |
255 | 249 |
|
256 | | - // Process shapeFlag for vapor and vdom components |
257 | | - // DynamicFragment (v-if, <component is/>) is processed in DynamicFragment.update |
| 250 | + // process shapeFlag |
258 | 251 | if (isVaporComponent(children)) { |
259 | 252 | children.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
260 | 253 | } else if (isInteropFragment(children)) { |
261 | 254 | children.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE |
262 | 255 | } else if (isDynamicFragment(children)) { |
263 | | - children.hooks = { |
264 | | - beforeUpdate(oldKey, newKey) { |
| 256 | + ;(children.beforeTeardown || (children.beforeTeardown = [])).push( |
| 257 | + (oldKey, nodes, scope) => { |
265 | 258 | processFragment(children) |
266 | | - const scope = children.scope |
267 | | - if (scope) { |
268 | | - keptAliveScopes.set(oldKey, scope) |
269 | | - } |
270 | | - }, |
271 | | - afterUpdate(newKey, nodes, scope) { |
272 | | - cacheFragment(children) |
273 | | - }, |
274 | | - getScope(key) { |
275 | | - const scope = keptAliveScopes.get(key) |
276 | | - if (scope) { |
277 | | - keptAliveScopes.delete(key) |
278 | | - return scope |
279 | | - } |
| 259 | + keptAliveScopes.set(oldKey, scope) |
| 260 | + return true |
280 | 261 | }, |
| 262 | + ) |
| 263 | + ;(children.beforeMount || (children.beforeMount = [])).push(() => |
| 264 | + cacheFragment(children), |
| 265 | + ) |
| 266 | + children.getScope = key => { |
| 267 | + const scope = keptAliveScopes.get(key) |
| 268 | + if (scope) { |
| 269 | + keptAliveScopes.delete(key) |
| 270 | + return scope |
| 271 | + } |
281 | 272 | } |
282 | | - cacheFragment(children) |
| 273 | + |
| 274 | + processFragment(children) |
283 | 275 | } |
284 | 276 |
|
285 | 277 | function pruneCache(filter: (name: string) => boolean) { |
@@ -321,29 +313,26 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({ |
321 | 313 | }, |
322 | 314 | }) |
323 | 315 |
|
324 | | -function getInnerBlock(block: Block): VaporComponentInstance | undefined { |
| 316 | +type InnerBlockResult = |
| 317 | + | [VaporFragment, true] |
| 318 | + | [VaporComponentInstance, false] |
| 319 | + | [undefined, false] |
| 320 | + |
| 321 | +function getInnerBlock(block: Block): InnerBlockResult { |
325 | 322 | if (isVaporComponent(block)) { |
326 | | - return block |
| 323 | + return [block, false] |
327 | 324 | } else if (isInteropFragment(block)) { |
328 | | - return block.vnode as any |
| 325 | + return [block, true] |
329 | 326 | } else if (isFragment(block)) { |
330 | 327 | return getInnerBlock(block.nodes) |
331 | 328 | } |
| 329 | + return [undefined, false] |
332 | 330 | } |
333 | 331 |
|
334 | 332 | function isInteropFragment(block: Block): block is VaporFragment { |
335 | 333 | return !!(isFragment(block) && block.vnode) |
336 | 334 | } |
337 | 335 |
|
338 | | -function findInteropFragment(block: Block): VaporFragment | undefined { |
339 | | - if (isInteropFragment(block)) { |
340 | | - return block |
341 | | - } |
342 | | - if (isFragment(block)) { |
343 | | - return findInteropFragment(block.nodes) |
344 | | - } |
345 | | -} |
346 | | - |
347 | 336 | function getInstanceFromCache( |
348 | 337 | cached: VaporComponentInstance | VaporFragment, |
349 | 338 | ): GenericComponentInstance { |
|
0 commit comments