createAsyncComponentContext,
currentInstance,
handleError,
- isKeepAlive,
markAsyncBoundary,
performAsyncHydrate,
+ shallowRef,
useAsyncComponentState,
watch,
} from '@vue/runtime-dom'
import { type TransitionOptions, insert, remove } from './block'
import { parentNode } from './dom/node'
import { setTransitionHooks } from './components/Transition'
-import type { KeepAliveInstance } from './components/KeepAlive'
/*@ __NO_SIDE_EFFECTS__ */
export function defineVaporAsyncComponent<T extends VaporComponent>(
},
} = createAsyncComponentContext<T, VaporComponent>(source)
+ const resolvedDef = shallowRef<VaporComponent>()
+
return defineVaporComponent({
name: 'VaporAsyncComponentWrapper',
)
},
+ // this accessor tracks the internal shallowRef `resolvedDef`.
+ // this allows KeepAlive to watch the resolution status.
get __asyncResolved() {
- return getResolvedComp()
+ return resolvedDef.value
},
setup() {
load()
.then(() => {
+ resolvedDef.value = getResolvedComp()!
loaded.value = true
- // if parent is keep-alive, re-evaluate caching
- if (instance.parent && isKeepAlive(instance.parent)) {
- ;(instance.parent as KeepAliveInstance).ctx.onAsyncResolve(instance)
- }
})
.catch(err => {
onError(err)
comp: VaporComponent,
) => VaporComponentInstance | VaporFragment | undefined
getStorageContainer: () => ParentNode
- onAsyncResolve: (asyncWrapper: VaporComponentInstance) => void
}
}
current = undefined
deactivate(instance, storageContainer)
},
- // called when async component resolves to evaluate caching
- onAsyncResolve: (asyncWrapper: VaporComponentInstance) => {
- if (shouldCache(asyncWrapper, props, false)) {
- asyncWrapper.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
- innerCacheBlock(asyncWrapper.type, asyncWrapper)
- }
- },
}
const innerCacheBlock = (
}
}
+ // for unresolved async wrapper, we need to watch the __asyncResolved
+ // property and cache the resolved component once it resolves.
+ const watchAsyncResolve = (instance: VaporComponentInstance) => {
+ if (!instance.type.__asyncResolved) {
+ watch(
+ () => instance.type.__asyncResolved,
+ resolved => {
+ if (resolved) cacheBlock()
+ },
+ { once: true },
+ )
+ }
+ }
+
// process shapeFlag
if (isVaporComponent(children)) {
children.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
if (isAsyncWrapper(children)) {
injectKeepAliveHooks(children.block as DynamicFragment)
+ watchAsyncResolve(children)
}
} else if (isInteropFragment(children)) {
children.vnode!.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
injectKeepAliveHooks(children)
if (isVaporComponent(children.nodes) && isAsyncWrapper(children.nodes)) {
injectKeepAliveHooks(children.nodes.block as DynamicFragment)
+ watchAsyncResolve(children.nodes)
}
}
) as GenericComponent & AsyncComponentInternalOptions
// for unresolved async components, don't cache yet
- // caching will be done in onAsyncResolve after the component resolves
+ // caching will be handled by the watcher in watchAsyncResolve
if (isAsync && !type.__asyncResolved) {
return false
}