From 4809325c075772ff945fe090ff686db42f75328f Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 27 Feb 2020 11:26:39 -0500 Subject: [PATCH] refactor(hydration): move fragment to seaprate function + skip normalization in optimized mode --- packages/runtime-core/src/hydration.ts | 69 +++++++++++++++----------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index ffe71ad3..844b30a0 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -39,7 +39,8 @@ export function createHydrationFunctions({ 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 @@ -49,18 +50,15 @@ export function createHydrationFunctions({ 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 @@ -69,7 +67,7 @@ export function createHydrationFunctions({ 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 @@ -83,7 +81,8 @@ export function createHydrationFunctions({ 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 @@ -123,8 +122,9 @@ export function createHydrationFunctions({ ) { hydrateChildren( el.firstChild, - vnode.children as VNode[], - parentComponent + vnode, + parentComponent, + optimized || vnode.dynamicChildren !== null ) } } @@ -133,32 +133,45 @@ export function createHydrationFunctions({ 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) } }