import { invokeDirectiveHook } from './directives'
import { ComponentPublicInstance } from './componentPublicInstanceProxy'
import { App, createAppAPI } from './apiApp'
-import { SuspenseBoundary, createSuspenseBoundary } from './suspense'
+import {
+ SuspenseBoundary,
+ createSuspenseBoundary,
+ normalizeSuspenseChildren
+} from './suspense'
import { provide } from './apiInject'
const prodEffectOptions = {
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null = null
) {
if (n1 == null) {
- const contentContainer = hostCreateElement('div')
-
- function retry() {
- processFragment(
- suspense.oldSubTree,
- suspense.subTree as HostVNode,
- contentContainer,
- null,
- parentComponent,
- isSVG,
- optimized
- )
- if (suspense.deps > 0) {
- // still pending.
- // TODO patch the fallback tree.
- } else {
- suspense.resolve()
- }
- }
-
function resolve() {
// unmount fallback tree
unmount(suspense.fallbackTree as HostVNode, parentComponent, true)
const suspense = (n2.suspense = createSuspenseBoundary(
n2,
parentSuspense,
- retry,
+ hostCreateElement('div'),
resolve
))
setCurrentInstance(null)
}
- // start mounting the subtree off-dom
+ const { content, fallback } = normalizeSuspenseChildren(n2)
+ suspense.subTree = content
+ suspense.fallbackTree = fallback
+
+ // start mounting the content subtree in an off-dom container
// TODO should buffer postQueue jobs on current boundary
- const subTree = (suspense.subTree = suspense.oldSubTree = childrenToFragment(
- n2
- ))
- processFragment(
+ patch(
null,
- subTree as HostVNode,
- contentContainer,
+ content,
+ suspense.container,
null,
parentComponent,
isSVG,
)
// now check if we have encountered any async deps
if (suspense.deps > 0) {
- // TODO mount the fallback tree.
- processEmptyNode(
+ // mount the fallback tree
+ patch(
null,
- (suspense.fallbackTree = createVNode(Empty)),
+ fallback,
container,
- anchor
+ anchor,
+ parentComponent,
+ isSVG,
+ optimized
)
+ n2.el = fallback.el
} else {
+ // Suspense has no async deps. Just resolve.
suspense.resolve()
}
} else {
HostElement
>
suspense.vnode = n2
+ const { content, fallback } = normalizeSuspenseChildren(n2)
const oldSubTree = (suspense.oldSubTree = suspense.subTree)
- const newContentTree = (suspense.subTree = childrenToFragment(n2))
+ suspense.subTree = content
+ const oldFallbackTree = (suspense.oldFallbackTree = suspense.fallbackTree)
+ suspense.fallbackTree = fallback
if (!suspense.isResolved) {
- suspense.retry()
+ patch(
+ oldSubTree,
+ content,
+ suspense.container,
+ null,
+ parentComponent,
+ isSVG,
+ optimized
+ )
+ if (suspense.deps > 0) {
+ // still pending. patch the fallback tree.
+ patch(
+ oldFallbackTree,
+ fallback,
+ container,
+ anchor,
+ parentComponent,
+ isSVG,
+ optimized
+ )
+ n2.el = fallback.el
+ } else {
+ suspense.resolve()
+ }
} else {
// just normal patch inner content as a fragment
- processFragment(
+ patch(
oldSubTree,
- newContentTree,
+ content,
container,
- null,
+ anchor,
parentComponent,
isSVG,
optimized
)
- n2.el = newContentTree.el
+ n2.el = content.el
}
}
}
- function childrenToFragment(vnode: HostVNode): HostVNode {
- return vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN
- ? createVNode(Fragment, null, vnode.children)
- : vnode.shapeFlag & ShapeFlags.TEXT_CHILDREN
- ? createVNode(Fragment, null, [vnode.children])
- : createVNode(Fragment, null, [])
- }
-
function processComponent(
n1: HostVNode | null,
n2: HostVNode,
-import { VNode } from './vnode'
+import { VNode, normalizeVNode } from './vnode'
+import { ShapeFlags } from '.'
export const SuspenseSymbol = __DEV__ ? Symbol('Suspense key') : Symbol()
> {
vnode: HostVNode
parent: SuspenseBoundary<HostNode, HostElement> | null
+ container: HostElement
subTree: HostVNode | null
oldSubTree: HostVNode | null
fallbackTree: HostVNode | null
deps: number
isResolved: boolean
bufferedJobs: Function[]
- retry(): void
resolve(): void
}
export function createSuspenseBoundary<HostNode, HostElement>(
vnode: VNode<HostNode, HostElement>,
parent: SuspenseBoundary<HostNode, HostElement> | null,
- retry: () => void,
+ container: HostElement,
resolve: () => void
): SuspenseBoundary<HostNode, HostElement> {
return {
vnode,
parent,
+ container,
deps: 0,
subTree: null,
oldSubTree: null,
oldFallbackTree: null,
isResolved: false,
bufferedJobs: [],
- retry,
resolve
}
}
+
+export function normalizeSuspenseChildren(
+ vnode: VNode
+): {
+ content: VNode
+ fallback: VNode
+} {
+ const { shapeFlag } = vnode
+ const children = vnode.children as any
+ if (shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
+ return {
+ content: normalizeVNode(children.default()),
+ fallback: normalizeVNode(children.fallback ? children.fallback() : null)
+ }
+ } else {
+ return {
+ content: normalizeVNode(children),
+ fallback: normalizeVNode(null)
+ }
+ }
+}