const hydrateNode = (
node: Node,
vnode: VNode,
- parentComponent: ComponentInternalInstance | null = null
+ parentComponent: ComponentInternalInstance | null = null,
+ optimized = false
): Node | null => {
const { type, shapeFlag } = vnode
vnode.el = node
case Static:
return node.nextSibling
case Fragment:
- const parent = node.parentNode!
- parent.insertBefore((vnode.el = createText('')), node)
- const next = hydrateChildren(
- node,
- vnode.children as VNode[],
- parentComponent
- )
- parent.insertBefore((vnode.anchor = createText('')), next)
- return next
+ return hydrateFragment(node, vnode, parentComponent, optimized)
default:
if (shapeFlag & ShapeFlags.ELEMENT) {
- return hydrateElement(node as Element, vnode, parentComponent)
+ return hydrateElement(
+ node as Element,
+ vnode,
+ parentComponent,
+ optimized
+ )
} else if (shapeFlag & ShapeFlags.COMPONENT) {
// when setting up the render effect, if the initial vnode already
// has .el set, the component will perform hydration instead of mount
const subTree = vnode.component!.subTree
return (subTree.anchor || subTree.el).nextSibling
} else if (shapeFlag & ShapeFlags.PORTAL) {
- hydratePortal(vnode, parentComponent)
+ hydratePortal(vnode, parentComponent, optimized)
return node.nextSibling
} else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
// TODO Suspense
const hydrateElement = (
el: Element,
vnode: VNode,
- parentComponent: ComponentInternalInstance | null
+ parentComponent: ComponentInternalInstance | null,
+ optimized: boolean
) => {
const { props, patchFlag } = vnode
// skip props & children if this is hoisted static nodes
) {
hydrateChildren(
el.firstChild,
- vnode.children as VNode[],
- parentComponent
+ vnode,
+ parentComponent,
+ optimized || vnode.dynamicChildren !== null
)
}
}
const hydrateChildren = (
node: Node | null,
- vnodes: VNode[],
- parentComponent: ComponentInternalInstance | null
+ vnode: VNode,
+ parentComponent: ComponentInternalInstance | null,
+ optimized: boolean
): Node | null => {
- for (let i = 0; node != null && i < vnodes.length; i++) {
- // TODO can skip normalizeVNode in optimized mode
- // (need hint on rendered markup?)
- const vnode = (vnodes[i] = normalizeVNode(vnodes[i]))
- node = hydrateNode(node, vnode, parentComponent)
+ const children = vnode.children as VNode[]
+ optimized = optimized || vnode.dynamicChildren !== null
+ for (let i = 0; node != null && i < children.length; i++) {
+ const vnode = optimized
+ ? children[i]
+ : (children[i] = normalizeVNode(children[i]))
+ node = hydrateNode(node, vnode, parentComponent, optimized)
}
return node
}
+ const hydrateFragment = (
+ node: Node,
+ vnode: VNode,
+ parentComponent: ComponentInternalInstance | null,
+ optimized: boolean
+ ) => {
+ const parent = node.parentNode!
+ parent.insertBefore((vnode.el = createText('')), node)
+ const next = hydrateChildren(node, vnode, parentComponent, optimized)
+ parent.insertBefore((vnode.anchor = createText('')), next)
+ return next
+ }
+
const hydratePortal = (
vnode: VNode,
- parentComponent: ComponentInternalInstance | null
+ parentComponent: ComponentInternalInstance | null,
+ optimized: boolean
) => {
const targetSelector = vnode.props && vnode.props.target
const target = (vnode.target = isString(targetSelector)
? document.querySelector(targetSelector)
: targetSelector)
if (target != null && vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
- hydrateChildren(
- target.firstChild,
- vnode.children as VNode[],
- parentComponent
- )
+ hydrateChildren(target.firstChild, vnode, parentComponent, optimized)
}
}