| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 | 
							- /**
 
-  * Virtual DOM patching algorithm based on Snabbdom by
 
-  * Simon Friis Vindum (@paldepind)
 
-  * Licensed under the MIT License
 
-  * https://github.com/paldepind/snabbdom/blob/master/LICENSE
 
-  *
 
-  * modified by Evan You (@yyx990803)
 
-  *
 
-  * Not type-checking this because this file is perf-critical and the cost
 
-  * of making flow understand it is not worth it.
 
-  */
 
- import VNode, { cloneVNode } from './vnode'
 
- import config from '../config'
 
- import { SSR_ATTR } from 'shared/constants'
 
- import { registerRef } from './modules/ref'
 
- import { traverse } from '../observer/traverse'
 
- import { activeInstance } from '../instance/lifecycle'
 
- import { isTextInputType } from 'web/util/element'
 
- import {
 
-   warn,
 
-   isDef,
 
-   isUndef,
 
-   isTrue,
 
-   makeMap,
 
-   isRegExp,
 
-   isPrimitive
 
- } from '../util/index'
 
- export const emptyNode = new VNode('', {}, [])
 
- const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
 
- function sameVnode (a, b) {
 
-   return (
 
-     a.key === b.key && (
 
-       (
 
-         a.tag === b.tag &&
 
-         a.isComment === b.isComment &&
 
-         isDef(a.data) === isDef(b.data) &&
 
-         sameInputType(a, b)
 
-       ) || (
 
-         isTrue(a.isAsyncPlaceholder) &&
 
-         a.asyncFactory === b.asyncFactory &&
 
-         isUndef(b.asyncFactory.error)
 
-       )
 
-     )
 
-   )
 
- }
 
- function sameInputType (a, b) {
 
-   if (a.tag !== 'input') return true
 
-   let i
 
-   const typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type
 
-   const typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type
 
-   return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
 
- }
 
- function createKeyToOldIdx (children, beginIdx, endIdx) {
 
-   let i, key
 
-   const map = {}
 
-   for (i = beginIdx; i <= endIdx; ++i) {
 
-     key = children[i].key
 
-     if (isDef(key)) map[key] = i
 
-   }
 
-   return map
 
- }
 
- export function createPatchFunction (backend) {
 
-   let i, j
 
-   const cbs = {}
 
-   const { modules, nodeOps } = backend
 
-   for (i = 0; i < hooks.length; ++i) {
 
-     cbs[hooks[i]] = []
 
-     for (j = 0; j < modules.length; ++j) {
 
-       if (isDef(modules[j][hooks[i]])) {
 
-         cbs[hooks[i]].push(modules[j][hooks[i]])
 
-       }
 
-     }
 
-   }
 
-   function emptyNodeAt (elm) {
 
-     return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
 
-   }
 
-   function createRmCb (childElm, listeners) {
 
-     function remove () {
 
-       if (--remove.listeners === 0) {
 
-         removeNode(childElm)
 
-       }
 
-     }
 
-     remove.listeners = listeners
 
-     return remove
 
-   }
 
-   function removeNode (el) {
 
-     const parent = nodeOps.parentNode(el)
 
-     // element may have already been removed due to v-html / v-text
 
-     if (isDef(parent)) {
 
-       nodeOps.removeChild(parent, el)
 
-     }
 
-   }
 
-   function isUnknownElement (vnode, inVPre) {
 
-     return (
 
-       !inVPre &&
 
-       !vnode.ns &&
 
-       !(
 
-         config.ignoredElements.length &&
 
-         config.ignoredElements.some(ignore => {
 
-           return isRegExp(ignore)
 
-             ? ignore.test(vnode.tag)
 
-             : ignore === vnode.tag
 
-         })
 
-       ) &&
 
-       config.isUnknownElement(vnode.tag)
 
-     )
 
-   }
 
-   let creatingElmInVPre = 0
 
-   function createElm (
 
-     vnode,
 
-     insertedVnodeQueue,
 
-     parentElm,
 
-     refElm,
 
-     nested,
 
-     ownerArray,
 
-     index
 
-   ) {
 
-     if (isDef(vnode.elm) && isDef(ownerArray)) {
 
-       // This vnode was used in a previous render!
 
-       // now it's used as a new node, overwriting its elm would cause
 
-       // potential patch errors down the road when it's used as an insertion
 
-       // reference node. Instead, we clone the node on-demand before creating
 
-       // associated DOM element for it.
 
-       vnode = ownerArray[index] = cloneVNode(vnode)
 
-     }
 
-     vnode.isRootInsert = !nested // for transition enter check
 
-     if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
 
-       return
 
-     }
 
-     const data = vnode.data
 
-     const children = vnode.children
 
-     const tag = vnode.tag
 
-     if (isDef(tag)) {
 
-       if (process.env.NODE_ENV !== 'production') {
 
-         if (data && data.pre) {
 
-           creatingElmInVPre++
 
-         }
 
-         if (isUnknownElement(vnode, creatingElmInVPre)) {
 
-           warn(
 
-             'Unknown custom element: <' + tag + '> - did you ' +
 
-             'register the component correctly? For recursive components, ' +
 
-             'make sure to provide the "name" option.',
 
-             vnode.context
 
-           )
 
-         }
 
-       }
 
-       vnode.elm = vnode.ns
 
-         ? nodeOps.createElementNS(vnode.ns, tag)
 
-         : nodeOps.createElement(tag, vnode)
 
-       setScope(vnode)
 
-       /* istanbul ignore if */
 
-       if (__WEEX__) {
 
-         // in Weex, the default insertion order is parent-first.
 
-         // List items can be optimized to use children-first insertion
 
-         // with append="tree".
 
-         const appendAsTree = isDef(data) && isTrue(data.appendAsTree)
 
-         if (!appendAsTree) {
 
-           if (isDef(data)) {
 
-             invokeCreateHooks(vnode, insertedVnodeQueue)
 
-           }
 
-           insert(parentElm, vnode.elm, refElm)
 
-         }
 
-         createChildren(vnode, children, insertedVnodeQueue)
 
-         if (appendAsTree) {
 
-           if (isDef(data)) {
 
-             invokeCreateHooks(vnode, insertedVnodeQueue)
 
-           }
 
-           insert(parentElm, vnode.elm, refElm)
 
-         }
 
-       } else {
 
-         createChildren(vnode, children, insertedVnodeQueue)
 
-         if (isDef(data)) {
 
-           invokeCreateHooks(vnode, insertedVnodeQueue)
 
-         }
 
-         insert(parentElm, vnode.elm, refElm)
 
-       }
 
-       if (process.env.NODE_ENV !== 'production' && data && data.pre) {
 
-         creatingElmInVPre--
 
-       }
 
-     } else if (isTrue(vnode.isComment)) {
 
-       vnode.elm = nodeOps.createComment(vnode.text)
 
-       insert(parentElm, vnode.elm, refElm)
 
-     } else {
 
-       vnode.elm = nodeOps.createTextNode(vnode.text)
 
-       insert(parentElm, vnode.elm, refElm)
 
-     }
 
-   }
 
-   function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
 
-     let i = vnode.data
 
-     if (isDef(i)) {
 
-       const isReactivated = isDef(vnode.componentInstance) && i.keepAlive
 
-       if (isDef(i = i.hook) && isDef(i = i.init)) {
 
-         i(vnode, false /* hydrating */)
 
-       }
 
-       // after calling the init hook, if the vnode is a child component
 
-       // it should've created a child instance and mounted it. the child
 
-       // component also has set the placeholder vnode's elm.
 
-       // in that case we can just return the element and be done.
 
-       if (isDef(vnode.componentInstance)) {
 
-         initComponent(vnode, insertedVnodeQueue)
 
-         insert(parentElm, vnode.elm, refElm)
 
-         if (isTrue(isReactivated)) {
 
-           reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)
 
-         }
 
-         return true
 
-       }
 
-     }
 
-   }
 
-   function initComponent (vnode, insertedVnodeQueue) {
 
-     if (isDef(vnode.data.pendingInsert)) {
 
-       insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert)
 
-       vnode.data.pendingInsert = null
 
-     }
 
-     vnode.elm = vnode.componentInstance.$el
 
-     if (isPatchable(vnode)) {
 
-       invokeCreateHooks(vnode, insertedVnodeQueue)
 
-       setScope(vnode)
 
-     } else {
 
-       // empty component root.
 
-       // skip all element-related modules except for ref (#3455)
 
-       registerRef(vnode)
 
-       // make sure to invoke the insert hook
 
-       insertedVnodeQueue.push(vnode)
 
-     }
 
-   }
 
-   function reactivateComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
 
-     let i
 
-     // hack for #4339: a reactivated component with inner transition
 
-     // does not trigger because the inner node's created hooks are not called
 
-     // again. It's not ideal to involve module-specific logic in here but
 
-     // there doesn't seem to be a better way to do it.
 
-     let innerNode = vnode
 
-     while (innerNode.componentInstance) {
 
-       innerNode = innerNode.componentInstance._vnode
 
-       if (isDef(i = innerNode.data) && isDef(i = i.transition)) {
 
-         for (i = 0; i < cbs.activate.length; ++i) {
 
-           cbs.activate[i](emptyNode, innerNode)
 
-         }
 
-         insertedVnodeQueue.push(innerNode)
 
-         break
 
-       }
 
-     }
 
-     // unlike a newly created component,
 
-     // a reactivated keep-alive component doesn't insert itself
 
-     insert(parentElm, vnode.elm, refElm)
 
-   }
 
-   function insert (parent, elm, ref) {
 
-     if (isDef(parent)) {
 
-       if (isDef(ref)) {
 
-         if (nodeOps.parentNode(ref) === parent) {
 
-           nodeOps.insertBefore(parent, elm, ref)
 
-         }
 
-       } else {
 
-         nodeOps.appendChild(parent, elm)
 
-       }
 
-     }
 
-   }
 
-   function createChildren (vnode, children, insertedVnodeQueue) {
 
-     if (Array.isArray(children)) {
 
-       if (process.env.NODE_ENV !== 'production') {
 
-         checkDuplicateKeys(children)
 
-       }
 
-       for (let i = 0; i < children.length; ++i) {
 
-         createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i)
 
-       }
 
-     } else if (isPrimitive(vnode.text)) {
 
-       nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)))
 
-     }
 
-   }
 
-   function isPatchable (vnode) {
 
-     while (vnode.componentInstance) {
 
-       vnode = vnode.componentInstance._vnode
 
-     }
 
-     return isDef(vnode.tag)
 
-   }
 
-   function invokeCreateHooks (vnode, insertedVnodeQueue) {
 
-     for (let i = 0; i < cbs.create.length; ++i) {
 
-       cbs.create[i](emptyNode, vnode)
 
-     }
 
-     i = vnode.data.hook // Reuse variable
 
-     if (isDef(i)) {
 
-       if (isDef(i.create)) i.create(emptyNode, vnode)
 
-       if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
 
-     }
 
-   }
 
-   // set scope id attribute for scoped CSS.
 
-   // this is implemented as a special case to avoid the overhead
 
-   // of going through the normal attribute patching process.
 
-   function setScope (vnode) {
 
-     let i
 
-     if (isDef(i = vnode.fnScopeId)) {
 
-       nodeOps.setStyleScope(vnode.elm, i)
 
-     } else {
 
-       let ancestor = vnode
 
-       while (ancestor) {
 
-         if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) {
 
-           nodeOps.setStyleScope(vnode.elm, i)
 
-         }
 
-         ancestor = ancestor.parent
 
-       }
 
-     }
 
-     // for slot content they should also get the scopeId from the host instance.
 
-     if (isDef(i = activeInstance) &&
 
-       i !== vnode.context &&
 
-       i !== vnode.fnContext &&
 
-       isDef(i = i.$options._scopeId)
 
-     ) {
 
-       nodeOps.setStyleScope(vnode.elm, i)
 
-     }
 
-   }
 
-   function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
 
-     for (; startIdx <= endIdx; ++startIdx) {
 
-       createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx)
 
-     }
 
-   }
 
-   function invokeDestroyHook (vnode) {
 
-     let i, j
 
-     const data = vnode.data
 
-     if (isDef(data)) {
 
-       if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode)
 
-       for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode)
 
-     }
 
-     if (isDef(i = vnode.children)) {
 
-       for (j = 0; j < vnode.children.length; ++j) {
 
-         invokeDestroyHook(vnode.children[j])
 
-       }
 
-     }
 
-   }
 
-   function removeVnodes (vnodes, startIdx, endIdx) {
 
-     for (; startIdx <= endIdx; ++startIdx) {
 
-       const ch = vnodes[startIdx]
 
-       if (isDef(ch)) {
 
-         if (isDef(ch.tag)) {
 
-           removeAndInvokeRemoveHook(ch)
 
-           invokeDestroyHook(ch)
 
-         } else { // Text node
 
-           removeNode(ch.elm)
 
-         }
 
-       }
 
-     }
 
-   }
 
-   function removeAndInvokeRemoveHook (vnode, rm) {
 
-     if (isDef(rm) || isDef(vnode.data)) {
 
-       let i
 
-       const listeners = cbs.remove.length + 1
 
-       if (isDef(rm)) {
 
-         // we have a recursively passed down rm callback
 
-         // increase the listeners count
 
-         rm.listeners += listeners
 
-       } else {
 
-         // directly removing
 
-         rm = createRmCb(vnode.elm, listeners)
 
-       }
 
-       // recursively invoke hooks on child component root node
 
-       if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {
 
-         removeAndInvokeRemoveHook(i, rm)
 
-       }
 
-       for (i = 0; i < cbs.remove.length; ++i) {
 
-         cbs.remove[i](vnode, rm)
 
-       }
 
-       if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {
 
-         i(vnode, rm)
 
-       } else {
 
-         rm()
 
-       }
 
-     } else {
 
-       removeNode(vnode.elm)
 
-     }
 
-   }
 
-   function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
 
-     let oldStartIdx = 0
 
-     let newStartIdx = 0
 
-     let oldEndIdx = oldCh.length - 1
 
-     let oldStartVnode = oldCh[0]
 
-     let oldEndVnode = oldCh[oldEndIdx]
 
-     let newEndIdx = newCh.length - 1
 
-     let newStartVnode = newCh[0]
 
-     let newEndVnode = newCh[newEndIdx]
 
-     let oldKeyToIdx, idxInOld, vnodeToMove, refElm
 
-     // removeOnly is a special flag used only by <transition-group>
 
-     // to ensure removed elements stay in correct relative positions
 
-     // during leaving transitions
 
-     const canMove = !removeOnly
 
-     if (process.env.NODE_ENV !== 'production') {
 
-       checkDuplicateKeys(newCh)
 
-     }
 
-     while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
 
-       if (isUndef(oldStartVnode)) {
 
-         oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
 
-       } else if (isUndef(oldEndVnode)) {
 
-         oldEndVnode = oldCh[--oldEndIdx]
 
-       } else if (sameVnode(oldStartVnode, newStartVnode)) {
 
-         patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
 
-         oldStartVnode = oldCh[++oldStartIdx]
 
-         newStartVnode = newCh[++newStartIdx]
 
-       } else if (sameVnode(oldEndVnode, newEndVnode)) {
 
-         patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
 
-         oldEndVnode = oldCh[--oldEndIdx]
 
-         newEndVnode = newCh[--newEndIdx]
 
-       } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
 
-         patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
 
-         canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
 
-         oldStartVnode = oldCh[++oldStartIdx]
 
-         newEndVnode = newCh[--newEndIdx]
 
-       } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
 
-         patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
 
-         canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
 
-         oldEndVnode = oldCh[--oldEndIdx]
 
-         newStartVnode = newCh[++newStartIdx]
 
-       } else {
 
-         if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
 
-         idxInOld = isDef(newStartVnode.key)
 
-           ? oldKeyToIdx[newStartVnode.key]
 
-           : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
 
-         if (isUndef(idxInOld)) { // New element
 
-           createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
 
-         } else {
 
-           vnodeToMove = oldCh[idxInOld]
 
-           if (sameVnode(vnodeToMove, newStartVnode)) {
 
-             patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
 
-             oldCh[idxInOld] = undefined
 
-             canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
 
-           } else {
 
-             // same key but different element. treat as new element
 
-             createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
 
-           }
 
-         }
 
-         newStartVnode = newCh[++newStartIdx]
 
-       }
 
-     }
 
-     if (oldStartIdx > oldEndIdx) {
 
-       refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
 
-       addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
 
-     } else if (newStartIdx > newEndIdx) {
 
-       removeVnodes(oldCh, oldStartIdx, oldEndIdx)
 
-     }
 
-   }
 
-   function checkDuplicateKeys (children) {
 
-     const seenKeys = {}
 
-     for (let i = 0; i < children.length; i++) {
 
-       const vnode = children[i]
 
-       const key = vnode.key
 
-       if (isDef(key)) {
 
-         if (seenKeys[key]) {
 
-           warn(
 
-             `Duplicate keys detected: '${key}'. This may cause an update error.`,
 
-             vnode.context
 
-           )
 
-         } else {
 
-           seenKeys[key] = true
 
-         }
 
-       }
 
-     }
 
-   }
 
-   function findIdxInOld (node, oldCh, start, end) {
 
-     for (let i = start; i < end; i++) {
 
-       const c = oldCh[i]
 
-       if (isDef(c) && sameVnode(node, c)) return i
 
-     }
 
-   }
 
-   function patchVnode (
 
-     oldVnode,
 
-     vnode,
 
-     insertedVnodeQueue,
 
-     ownerArray,
 
-     index,
 
-     removeOnly
 
-   ) {
 
-     if (oldVnode === vnode) {
 
-       return
 
-     }
 
-     if (isDef(vnode.elm) && isDef(ownerArray)) {
 
-       // clone reused vnode
 
-       vnode = ownerArray[index] = cloneVNode(vnode)
 
-     }
 
-     const elm = vnode.elm = oldVnode.elm
 
-     if (isTrue(oldVnode.isAsyncPlaceholder)) {
 
-       if (isDef(vnode.asyncFactory.resolved)) {
 
-         hydrate(oldVnode.elm, vnode, insertedVnodeQueue)
 
-       } else {
 
-         vnode.isAsyncPlaceholder = true
 
-       }
 
-       return
 
-     }
 
-     // reuse element for static trees.
 
-     // note we only do this if the vnode is cloned -
 
-     // if the new node is not cloned it means the render functions have been
 
-     // reset by the hot-reload-api and we need to do a proper re-render.
 
-     if (isTrue(vnode.isStatic) &&
 
-       isTrue(oldVnode.isStatic) &&
 
-       vnode.key === oldVnode.key &&
 
-       (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
 
-     ) {
 
-       vnode.componentInstance = oldVnode.componentInstance
 
-       return
 
-     }
 
-     let i
 
-     const data = vnode.data
 
-     if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
 
-       i(oldVnode, vnode)
 
-     }
 
-     const oldCh = oldVnode.children
 
-     const ch = vnode.children
 
-     if (isDef(data) && isPatchable(vnode)) {
 
-       for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode)
 
-       if (isDef(i = data.hook) && isDef(i = i.update)) i(oldVnode, vnode)
 
-     }
 
-     if (isUndef(vnode.text)) {
 
-       if (isDef(oldCh) && isDef(ch)) {
 
-         if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
 
-       } else if (isDef(ch)) {
 
-         if (process.env.NODE_ENV !== 'production') {
 
-           checkDuplicateKeys(ch)
 
-         }
 
-         if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
 
-         addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
 
-       } else if (isDef(oldCh)) {
 
-         removeVnodes(oldCh, 0, oldCh.length - 1)
 
-       } else if (isDef(oldVnode.text)) {
 
-         nodeOps.setTextContent(elm, '')
 
-       }
 
-     } else if (oldVnode.text !== vnode.text) {
 
-       nodeOps.setTextContent(elm, vnode.text)
 
-     }
 
-     if (isDef(data)) {
 
-       if (isDef(i = data.hook) && isDef(i = i.postpatch)) i(oldVnode, vnode)
 
-     }
 
-   }
 
-   function invokeInsertHook (vnode, queue, initial) {
 
-     // delay insert hooks for component root nodes, invoke them after the
 
-     // element is really inserted
 
-     if (isTrue(initial) && isDef(vnode.parent)) {
 
-       vnode.parent.data.pendingInsert = queue
 
-     } else {
 
-       for (let i = 0; i < queue.length; ++i) {
 
-         queue[i].data.hook.insert(queue[i])
 
-       }
 
-     }
 
-   }
 
-   let hydrationBailed = false
 
-   // list of modules that can skip create hook during hydration because they
 
-   // are already rendered on the client or has no need for initialization
 
-   // Note: style is excluded because it relies on initial clone for future
 
-   // deep updates (#7063).
 
-   const isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key')
 
-   // Note: this is a browser-only function so we can assume elms are DOM nodes.
 
-   function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {
 
-     let i
 
-     const { tag, data, children } = vnode
 
-     inVPre = inVPre || (data && data.pre)
 
-     vnode.elm = elm
 
-     if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
 
-       vnode.isAsyncPlaceholder = true
 
-       return true
 
-     }
 
-     // assert node match
 
-     if (process.env.NODE_ENV !== 'production') {
 
-       if (!assertNodeMatch(elm, vnode, inVPre)) {
 
-         return false
 
-       }
 
-     }
 
-     if (isDef(data)) {
 
-       if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode, true /* hydrating */)
 
-       if (isDef(i = vnode.componentInstance)) {
 
-         // child component. it should have hydrated its own tree.
 
-         initComponent(vnode, insertedVnodeQueue)
 
-         return true
 
-       }
 
-     }
 
-     if (isDef(tag)) {
 
-       if (isDef(children)) {
 
-         // empty element, allow client to pick up and populate children
 
-         if (!elm.hasChildNodes()) {
 
-           createChildren(vnode, children, insertedVnodeQueue)
 
-         } else {
 
-           // v-html and domProps: innerHTML
 
-           if (isDef(i = data) && isDef(i = i.domProps) && isDef(i = i.innerHTML)) {
 
-             if (i !== elm.innerHTML) {
 
-               /* istanbul ignore if */
 
-               if (process.env.NODE_ENV !== 'production' &&
 
-                 typeof console !== 'undefined' &&
 
-                 !hydrationBailed
 
-               ) {
 
-                 hydrationBailed = true
 
-                 console.warn('Parent: ', elm)
 
-                 console.warn('server innerHTML: ', i)
 
-                 console.warn('client innerHTML: ', elm.innerHTML)
 
-               }
 
-               return false
 
-             }
 
-           } else {
 
-             // iterate and compare children lists
 
-             let childrenMatch = true
 
-             let childNode = elm.firstChild
 
-             for (let i = 0; i < children.length; i++) {
 
-               if (!childNode || !hydrate(childNode, children[i], insertedVnodeQueue, inVPre)) {
 
-                 childrenMatch = false
 
-                 break
 
-               }
 
-               childNode = childNode.nextSibling
 
-             }
 
-             // if childNode is not null, it means the actual childNodes list is
 
-             // longer than the virtual children list.
 
-             if (!childrenMatch || childNode) {
 
-               /* istanbul ignore if */
 
-               if (process.env.NODE_ENV !== 'production' &&
 
-                 typeof console !== 'undefined' &&
 
-                 !hydrationBailed
 
-               ) {
 
-                 hydrationBailed = true
 
-                 console.warn('Parent: ', elm)
 
-                 console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children)
 
-               }
 
-               return false
 
-             }
 
-           }
 
-         }
 
-       }
 
-       if (isDef(data)) {
 
-         let fullInvoke = false
 
-         for (const key in data) {
 
-           if (!isRenderedModule(key)) {
 
-             fullInvoke = true
 
-             invokeCreateHooks(vnode, insertedVnodeQueue)
 
-             break
 
-           }
 
-         }
 
-         if (!fullInvoke && data['class']) {
 
-           // ensure collecting deps for deep class bindings for future updates
 
-           traverse(data['class'])
 
-         }
 
-       }
 
-     } else if (elm.data !== vnode.text) {
 
-       elm.data = vnode.text
 
-     }
 
-     return true
 
-   }
 
-   function assertNodeMatch (node, vnode, inVPre) {
 
-     if (isDef(vnode.tag)) {
 
-       return vnode.tag.indexOf('vue-component') === 0 || (
 
-         !isUnknownElement(vnode, inVPre) &&
 
-         vnode.tag.toLowerCase() === (node.tagName && node.tagName.toLowerCase())
 
-       )
 
-     } else {
 
-       return node.nodeType === (vnode.isComment ? 8 : 3)
 
-     }
 
-   }
 
-   return function patch (oldVnode, vnode, hydrating, removeOnly) {
 
-     if (isUndef(vnode)) {
 
-       if (isDef(oldVnode)) invokeDestroyHook(oldVnode)
 
-       return
 
-     }
 
-     let isInitialPatch = false
 
-     const insertedVnodeQueue = []
 
-     if (isUndef(oldVnode)) {
 
-       // empty mount (likely as component), create new root element
 
-       isInitialPatch = true
 
-       createElm(vnode, insertedVnodeQueue)
 
-     } else {
 
-       const isRealElement = isDef(oldVnode.nodeType)
 
-       if (!isRealElement && sameVnode(oldVnode, vnode)) {
 
-         // patch existing root node
 
-         patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly)
 
-       } else {
 
-         if (isRealElement) {
 
-           // mounting to a real element
 
-           // check if this is server-rendered content and if we can perform
 
-           // a successful hydration.
 
-           if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
 
-             oldVnode.removeAttribute(SSR_ATTR)
 
-             hydrating = true
 
-           }
 
-           if (isTrue(hydrating)) {
 
-             if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
 
-               invokeInsertHook(vnode, insertedVnodeQueue, true)
 
-               return oldVnode
 
-             } else if (process.env.NODE_ENV !== 'production') {
 
-               warn(
 
-                 'The client-side rendered virtual DOM tree is not matching ' +
 
-                 'server-rendered content. This is likely caused by incorrect ' +
 
-                 'HTML markup, for example nesting block-level elements inside ' +
 
-                 '<p>, or missing <tbody>. Bailing hydration and performing ' +
 
-                 'full client-side render.'
 
-               )
 
-             }
 
-           }
 
-           // either not server-rendered, or hydration failed.
 
-           // create an empty node and replace it
 
-           oldVnode = emptyNodeAt(oldVnode)
 
-         }
 
-         // replacing existing element
 
-         const oldElm = oldVnode.elm
 
-         const parentElm = nodeOps.parentNode(oldElm)
 
-         // create new node
 
-         createElm(
 
-           vnode,
 
-           insertedVnodeQueue,
 
-           // extremely rare edge case: do not insert if old element is in a
 
-           // leaving transition. Only happens when combining transition +
 
-           // keep-alive + HOCs. (#4590)
 
-           oldElm._leaveCb ? null : parentElm,
 
-           nodeOps.nextSibling(oldElm)
 
-         )
 
-         // update parent placeholder node element, recursively
 
-         if (isDef(vnode.parent)) {
 
-           let ancestor = vnode.parent
 
-           const patchable = isPatchable(vnode)
 
-           while (ancestor) {
 
-             for (let i = 0; i < cbs.destroy.length; ++i) {
 
-               cbs.destroy[i](ancestor)
 
-             }
 
-             ancestor.elm = vnode.elm
 
-             if (patchable) {
 
-               for (let i = 0; i < cbs.create.length; ++i) {
 
-                 cbs.create[i](emptyNode, ancestor)
 
-               }
 
-               // #6513
 
-               // invoke insert hooks that may have been merged by create hooks.
 
-               // e.g. for directives that uses the "inserted" hook.
 
-               const insert = ancestor.data.hook.insert
 
-               if (insert.merged) {
 
-                 // start at index 1 to avoid re-invoking component mounted hook
 
-                 for (let i = 1; i < insert.fns.length; i++) {
 
-                   insert.fns[i]()
 
-                 }
 
-               }
 
-             } else {
 
-               registerRef(ancestor)
 
-             }
 
-             ancestor = ancestor.parent
 
-           }
 
-         }
 
-         // destroy old node
 
-         if (isDef(parentElm)) {
 
-           removeVnodes([oldVnode], 0, 0)
 
-         } else if (isDef(oldVnode.tag)) {
 
-           invokeDestroyHook(oldVnode)
 
-         }
 
-       }
 
-     }
 
-     invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)
 
-     return vnode.elm
 
-   }
 
- }
 
 
  |