1/**2 * Virtual DOM patching algorithm based on Snabbdom by3 * Simon Friis Vindum (@paldepind)4 * Licensed under the MIT License5 * https://github.com/paldepind/snabbdom/blob/master/LICENSE6 *7 * modified by Evan You (@yyx990803)8 *9 * Not type-checking this because this file is perf-critical and the cost10 * of making flow understand it is not worth it.11 */1213import VNode, { cloneVNode } from './vnode'14import config from '../config'15import { SSR_ATTR } from 'shared/constants'16import { registerRef } from './modules/template-ref'17import { traverse } from '../observer/traverse'18import { activeInstance } from '../instance/lifecycle'19import { isTextInputType } from 'web/util/element'2021import {22 warn,23 isDef,24 isUndef,25 isTrue,26 isArray,27 makeMap,28 isRegExp,29 isPrimitive30} from '../util/index'3132export const emptyNode = new VNode('', {}, [])3334const hooks = ['create', 'activate', 'update', 'remove', 'destroy']3536function sameVnode(a, b) {37 return (38 a.key === b.key &&39 a.asyncFactory === b.asyncFactory &&40 ((a.tag === b.tag &&41 a.isComment === b.isComment &&42 isDef(a.data) === isDef(b.data) &&43 sameInputType(a, b)) ||44 (isTrue(a.isAsyncPlaceholder) && isUndef(b.asyncFactory.error)))45 )46}4748function sameInputType(a, b) {49 if (a.tag !== 'input') return true50 let i51 const typeA = isDef((i = a.data)) && isDef((i = i.attrs)) && i.type52 const typeB = isDef((i = b.data)) && isDef((i = i.attrs)) && i.type53 return typeA === typeB || (isTextInputType(typeA) && isTextInputType(typeB))54}5556function createKeyToOldIdx(children, beginIdx, endIdx) {57 let i, key58 const map = {}59 for (i = beginIdx; i <= endIdx; ++i) {60 key = children[i].key61 if (isDef(key)) map[key] = i62 }63 return map64}6566export function createPatchFunction(backend) {67 let i, j68 const cbs: any = {}6970 const { modules, nodeOps } = backend7172 for (i = 0; i < hooks.length; ++i) {73 cbs[hooks[i]] = []74 for (j = 0; j < modules.length; ++j) {75 if (isDef(modules[j][hooks[i]])) {76 cbs[hooks[i]].push(modules[j][hooks[i]])77 }78 }79 }8081 function emptyNodeAt(elm) {82 return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)83 }8485 function createRmCb(childElm, listeners) {86 function remove() {87 if (--remove.listeners === 0) {88 removeNode(childElm)89 }90 }91 remove.listeners = listeners92 return remove93 }9495 function removeNode(el) {96 const parent = nodeOps.parentNode(el)97 // element may have already been removed due to v-html / v-text98 if (isDef(parent)) {99 nodeOps.removeChild(parent, el)100 }101 }102103 function isUnknownElement(vnode, inVPre) {104 return (105 !inVPre &&106 !vnode.ns &&107 !(108 config.ignoredElements.length &&109 config.ignoredElements.some(ignore => {110 return isRegExp(ignore)111 ? ignore.test(vnode.tag)112 : ignore === vnode.tag113 })114 ) &&115 config.isUnknownElement(vnode.tag)116 )117 }118119 let creatingElmInVPre = 0120121 function createElm(122 vnode,123 insertedVnodeQueue,124 parentElm?: any,125 refElm?: any,126 nested?: any,127 ownerArray?: any,128 index?: any129 ) {130 if (isDef(vnode.elm) && isDef(ownerArray)) {131 // This vnode was used in a previous render!132 // now it's used as a new node, overwriting its elm would cause133 // potential patch errors down the road when it's used as an insertion134 // reference node. Instead, we clone the node on-demand before creating135 // associated DOM element for it.136 vnode = ownerArray[index] = cloneVNode(vnode)137 }138139 vnode.isRootInsert = !nested // for transition enter check140 if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {141 return142 }143144 const data = vnode.data145 const children = vnode.children146 const tag = vnode.tag147 if (isDef(tag)) {148 if (__DEV__) {149 if (data && data.pre) {150 creatingElmInVPre++151 }152 if (isUnknownElement(vnode, creatingElmInVPre)) {153 warn(154 'Unknown custom element: <' +155 tag +156 '> - did you ' +157 'register the component correctly? For recursive components, ' +158 'make sure to provide the "name" option.',159 vnode.context160 )161 }162 }163164 vnode.elm = vnode.ns165 ? nodeOps.createElementNS(vnode.ns, tag)166 : nodeOps.createElement(tag, vnode)167 setScope(vnode)168169 createChildren(vnode, children, insertedVnodeQueue)170 if (isDef(data)) {171 invokeCreateHooks(vnode, insertedVnodeQueue)172 }173 insert(parentElm, vnode.elm, refElm)174175 if (__DEV__ && data && data.pre) {176 creatingElmInVPre--177 }178 } else if (isTrue(vnode.isComment)) {179 vnode.elm = nodeOps.createComment(vnode.text)180 insert(parentElm, vnode.elm, refElm)181 } else {182 vnode.elm = nodeOps.createTextNode(vnode.text)183 insert(parentElm, vnode.elm, refElm)184 }185 }186187 function createComponent(vnode, insertedVnodeQueue, parentElm, refElm) {188 let i = vnode.data189 if (isDef(i)) {190 const isReactivated = isDef(vnode.componentInstance) && i.keepAlive191 if (isDef((i = i.hook)) && isDef((i = i.init))) {192 i(vnode, false /* hydrating */)193 }194 // after calling the init hook, if the vnode is a child component195 // it should've created a child instance and mounted it. the child196 // component also has set the placeholder vnode's elm.197 // in that case we can just return the element and be done.198 if (isDef(vnode.componentInstance)) {199 initComponent(vnode, insertedVnodeQueue)200 insert(parentElm, vnode.elm, refElm)201 if (isTrue(isReactivated)) {202 reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)203 }204 return true205 }206 }207 }208209 function initComponent(vnode, insertedVnodeQueue) {210 if (isDef(vnode.data.pendingInsert)) {211 insertedVnodeQueue.push.apply(212 insertedVnodeQueue,213 vnode.data.pendingInsert214 )215 vnode.data.pendingInsert = null216 }217 vnode.elm = vnode.componentInstance.$el218 if (isPatchable(vnode)) {219 invokeCreateHooks(vnode, insertedVnodeQueue)220 setScope(vnode)221 } else {222 // empty component root.223 // skip all element-related modules except for ref (#3455)224 registerRef(vnode)225 // make sure to invoke the insert hook226 insertedVnodeQueue.push(vnode)227 }228 }229230 function reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm) {231 let i232 // hack for #4339: a reactivated component with inner transition233 // does not trigger because the inner node's created hooks are not called234 // again. It's not ideal to involve module-specific logic in here but235 // there doesn't seem to be a better way to do it.236 let innerNode = vnode237 while (innerNode.componentInstance) {238 innerNode = innerNode.componentInstance._vnode239 if (isDef((i = innerNode.data)) && isDef((i = i.transition))) {240 for (i = 0; i < cbs.activate.length; ++i) {241 cbs.activate[i](emptyNode, innerNode)242 }243 insertedVnodeQueue.push(innerNode)244 break245 }246 }247 // unlike a newly created component,248 // a reactivated keep-alive component doesn't insert itself249 insert(parentElm, vnode.elm, refElm)250 }251252 function insert(parent, elm, ref) {253 if (isDef(parent)) {254 if (isDef(ref)) {255 if (nodeOps.parentNode(ref) === parent) {256 nodeOps.insertBefore(parent, elm, ref)257 }258 } else {259 nodeOps.appendChild(parent, elm)260 }261 }262 }263264 function createChildren(vnode, children, insertedVnodeQueue) {265 if (isArray(children)) {266 if (__DEV__) {267 checkDuplicateKeys(children)268 }269 for (let i = 0; i < children.length; ++i) {270 createElm(271 children[i],272 insertedVnodeQueue,273 vnode.elm,274 null,275 true,276 children,277 i278 )279 }280 } else if (isPrimitive(vnode.text)) {281 nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)))282 }283 }284285 function isPatchable(vnode) {286 while (vnode.componentInstance) {287 vnode = vnode.componentInstance._vnode288 }289 return isDef(vnode.tag)290 }291292 function invokeCreateHooks(vnode, insertedVnodeQueue) {293 for (let i = 0; i < cbs.create.length; ++i) {294 cbs.create[i](emptyNode, vnode)295 }296 i = vnode.data.hook // Reuse variable297 if (isDef(i)) {298 if (isDef(i.create)) i.create(emptyNode, vnode)299 if (isDef(i.insert)) insertedVnodeQueue.push(vnode)300 }301 }302303 // set scope id attribute for scoped CSS.304 // this is implemented as a special case to avoid the overhead305 // of going through the normal attribute patching process.306 function setScope(vnode) {307 let i308 if (isDef((i = vnode.fnScopeId))) {309 nodeOps.setStyleScope(vnode.elm, i)310 } else {311 let ancestor = vnode312 while (ancestor) {313 if (isDef((i = ancestor.context)) && isDef((i = i.$options._scopeId))) {314 nodeOps.setStyleScope(vnode.elm, i)315 }316 ancestor = ancestor.parent317 }318 }319 // for slot content they should also get the scopeId from the host instance.320 if (321 isDef((i = activeInstance)) &&322 i !== vnode.context &&323 i !== vnode.fnContext &&324 isDef((i = i.$options._scopeId))325 ) {326 nodeOps.setStyleScope(vnode.elm, i)327 }328 }329330 function addVnodes(331 parentElm,332 refElm,333 vnodes,334 startIdx,335 endIdx,336 insertedVnodeQueue337 ) {338 for (; startIdx <= endIdx; ++startIdx) {339 createElm(340 vnodes[startIdx],341 insertedVnodeQueue,342 parentElm,343 refElm,344 false,345 vnodes,346 startIdx347 )348 }349 }350351 function invokeDestroyHook(vnode) {352 let i, j353 const data = vnode.data354 if (isDef(data)) {355 if (isDef((i = data.hook)) && isDef((i = i.destroy))) i(vnode)356 for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode)357 }358 if (isDef((i = vnode.children))) {359 for (j = 0; j < vnode.children.length; ++j) {360 invokeDestroyHook(vnode.children[j])361 }362 }363 }364365 function removeVnodes(vnodes, startIdx, endIdx) {366 for (; startIdx <= endIdx; ++startIdx) {367 const ch = vnodes[startIdx]368 if (isDef(ch)) {369 if (isDef(ch.tag)) {370 removeAndInvokeRemoveHook(ch)371 invokeDestroyHook(ch)372 } else {373 // Text node374 removeNode(ch.elm)375 }376 }377 }378 }379380 function removeAndInvokeRemoveHook(vnode, rm?: any) {381 if (isDef(rm) || isDef(vnode.data)) {382 let i383 const listeners = cbs.remove.length + 1384 if (isDef(rm)) {385 // we have a recursively passed down rm callback386 // increase the listeners count387 rm.listeners += listeners388 } else {389 // directly removing390 rm = createRmCb(vnode.elm, listeners)391 }392 // recursively invoke hooks on child component root node393 if (394 isDef((i = vnode.componentInstance)) &&395 isDef((i = i._vnode)) &&396 isDef(i.data)397 ) {398 removeAndInvokeRemoveHook(i, rm)399 }400 for (i = 0; i < cbs.remove.length; ++i) {401 cbs.remove[i](vnode, rm)402 }403 if (isDef((i = vnode.data.hook)) && isDef((i = i.remove))) {404 i(vnode, rm)405 } else {406 rm()407 }408 } else {409 removeNode(vnode.elm)410 }411 }412413 function updateChildren(414 parentElm,415 oldCh,416 newCh,417 insertedVnodeQueue,418 removeOnly419 ) {420 let oldStartIdx = 0421 let newStartIdx = 0422 let oldEndIdx = oldCh.length - 1423 let oldStartVnode = oldCh[0]424 let oldEndVnode = oldCh[oldEndIdx]425 let newEndIdx = newCh.length - 1426 let newStartVnode = newCh[0]427 let newEndVnode = newCh[newEndIdx]428 let oldKeyToIdx, idxInOld, vnodeToMove, refElm429430 // removeOnly is a special flag used only by <transition-group>431 // to ensure removed elements stay in correct relative positions432 // during leaving transitions433 const canMove = !removeOnly434435 if (__DEV__) {436 checkDuplicateKeys(newCh)437 }438439 while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {440 if (isUndef(oldStartVnode)) {441 oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left442 } else if (isUndef(oldEndVnode)) {443 oldEndVnode = oldCh[--oldEndIdx]444 } else if (sameVnode(oldStartVnode, newStartVnode)) {445 patchVnode(446 oldStartVnode,447 newStartVnode,448 insertedVnodeQueue,449 newCh,450 newStartIdx451 )452 oldStartVnode = oldCh[++oldStartIdx]453 newStartVnode = newCh[++newStartIdx]454 } else if (sameVnode(oldEndVnode, newEndVnode)) {455 patchVnode(456 oldEndVnode,457 newEndVnode,458 insertedVnodeQueue,459 newCh,460 newEndIdx461 )462 oldEndVnode = oldCh[--oldEndIdx]463 newEndVnode = newCh[--newEndIdx]464 } else if (sameVnode(oldStartVnode, newEndVnode)) {465 // Vnode moved right466 patchVnode(467 oldStartVnode,468 newEndVnode,469 insertedVnodeQueue,470 newCh,471 newEndIdx472 )473 canMove &&474 nodeOps.insertBefore(475 parentElm,476 oldStartVnode.elm,477 nodeOps.nextSibling(oldEndVnode.elm)478 )479 oldStartVnode = oldCh[++oldStartIdx]480 newEndVnode = newCh[--newEndIdx]481 } else if (sameVnode(oldEndVnode, newStartVnode)) {482 // Vnode moved left483 patchVnode(484 oldEndVnode,485 newStartVnode,486 insertedVnodeQueue,487 newCh,488 newStartIdx489 )490 canMove &&491 nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)492 oldEndVnode = oldCh[--oldEndIdx]493 newStartVnode = newCh[++newStartIdx]494 } else {495 if (isUndef(oldKeyToIdx))496 oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)497 idxInOld = isDef(newStartVnode.key)498 ? oldKeyToIdx[newStartVnode.key]499 : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)500 if (isUndef(idxInOld)) {501 // New element502 createElm(503 newStartVnode,504 insertedVnodeQueue,505 parentElm,506 oldStartVnode.elm,507 false,508 newCh,509 newStartIdx510 )511 } else {512 vnodeToMove = oldCh[idxInOld]513 if (sameVnode(vnodeToMove, newStartVnode)) {514 patchVnode(515 vnodeToMove,516 newStartVnode,517 insertedVnodeQueue,518 newCh,519 newStartIdx520 )521 oldCh[idxInOld] = undefined522 canMove &&523 nodeOps.insertBefore(524 parentElm,525 vnodeToMove.elm,526 oldStartVnode.elm527 )528 } else {529 // same key but different element. treat as new element530 createElm(531 newStartVnode,532 insertedVnodeQueue,533 parentElm,534 oldStartVnode.elm,535 false,536 newCh,537 newStartIdx538 )539 }540 }541 newStartVnode = newCh[++newStartIdx]542 }543 }544 if (oldStartIdx > oldEndIdx) {545 refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm546 addVnodes(547 parentElm,548 refElm,549 newCh,550 newStartIdx,551 newEndIdx,552 insertedVnodeQueue553 )554 } else if (newStartIdx > newEndIdx) {555 removeVnodes(oldCh, oldStartIdx, oldEndIdx)556 }557 }558559 function checkDuplicateKeys(children) {560 const seenKeys = {}561 for (let i = 0; i < children.length; i++) {562 const vnode = children[i]563 const key = vnode.key564 if (isDef(key)) {565 if (seenKeys[key]) {566 warn(567 `Duplicate keys detected: '${key}'. This may cause an update error.`,568 vnode.context569 )570 } else {571 seenKeys[key] = true572 }573 }574 }575 }576577 function findIdxInOld(node, oldCh, start, end) {578 for (let i = start; i < end; i++) {579 const c = oldCh[i]580 if (isDef(c) && sameVnode(node, c)) return i581 }582 }583584 function patchVnode(585 oldVnode,586 vnode,587 insertedVnodeQueue,588 ownerArray,589 index,590 removeOnly?: any591 ) {592 if (oldVnode === vnode) {593 return594 }595596 if (isDef(vnode.elm) && isDef(ownerArray)) {597 // clone reused vnode598 vnode = ownerArray[index] = cloneVNode(vnode)599 }600601 const elm = (vnode.elm = oldVnode.elm)602603 if (isTrue(oldVnode.isAsyncPlaceholder)) {604 if (isDef(vnode.asyncFactory.resolved)) {605 hydrate(oldVnode.elm, vnode, insertedVnodeQueue)606 } else {607 vnode.isAsyncPlaceholder = true608 }609 return610 }611612 // reuse element for static trees.613 // note we only do this if the vnode is cloned -614 // if the new node is not cloned it means the render functions have been615 // reset by the hot-reload-api and we need to do a proper re-render.616 if (617 isTrue(vnode.isStatic) &&618 isTrue(oldVnode.isStatic) &&619 vnode.key === oldVnode.key &&620 (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))621 ) {622 vnode.componentInstance = oldVnode.componentInstance623 return624 }625626 let i627 const data = vnode.data628 if (isDef(data) && isDef((i = data.hook)) && isDef((i = i.prepatch))) {629 i(oldVnode, vnode)630 }631632 const oldCh = oldVnode.children633 const ch = vnode.children634 if (isDef(data) && isPatchable(vnode)) {635 for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode)636 if (isDef((i = data.hook)) && isDef((i = i.update))) i(oldVnode, vnode)637 }638 if (isUndef(vnode.text)) {639 if (isDef(oldCh) && isDef(ch)) {640 if (oldCh !== ch)641 updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)642 } else if (isDef(ch)) {643 if (__DEV__) {644 checkDuplicateKeys(ch)645 }646 if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')647 addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)648 } else if (isDef(oldCh)) {649 removeVnodes(oldCh, 0, oldCh.length - 1)650 } else if (isDef(oldVnode.text)) {651 nodeOps.setTextContent(elm, '')652 }653 } else if (oldVnode.text !== vnode.text) {654 nodeOps.setTextContent(elm, vnode.text)655 }656 if (isDef(data)) {657 if (isDef((i = data.hook)) && isDef((i = i.postpatch))) i(oldVnode, vnode)658 }659 }660661 function invokeInsertHook(vnode, queue, initial) {662 // delay insert hooks for component root nodes, invoke them after the663 // element is really inserted664 if (isTrue(initial) && isDef(vnode.parent)) {665 vnode.parent.data.pendingInsert = queue666 } else {667 for (let i = 0; i < queue.length; ++i) {668 queue[i].data.hook.insert(queue[i])669 }670 }671 }672673 let hydrationBailed = false674 // list of modules that can skip create hook during hydration because they675 // are already rendered on the client or has no need for initialization676 // Note: style is excluded because it relies on initial clone for future677 // deep updates (#7063).678 const isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key')679680 // Note: this is a browser-only function so we can assume elms are DOM nodes.681 function hydrate(elm, vnode, insertedVnodeQueue, inVPre?: boolean) {682 let i683 const { tag, data, children } = vnode684 inVPre = inVPre || (data && data.pre)685 vnode.elm = elm686687 if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {688 vnode.isAsyncPlaceholder = true689 return true690 }691 // assert node match692 if (__DEV__) {693 if (!assertNodeMatch(elm, vnode, inVPre)) {694 return false695 }696 }697 if (isDef(data)) {698 if (isDef((i = data.hook)) && isDef((i = i.init)))699 i(vnode, true /* hydrating */)700 if (isDef((i = vnode.componentInstance))) {701 // child component. it should have hydrated its own tree.702 initComponent(vnode, insertedVnodeQueue)703 return true704 }705 }706 if (isDef(tag)) {707 if (isDef(children)) {708 // empty element, allow client to pick up and populate children709 if (!elm.hasChildNodes()) {710 createChildren(vnode, children, insertedVnodeQueue)711 } else {712 // v-html and domProps: innerHTML713 if (714 isDef((i = data)) &&715 isDef((i = i.domProps)) &&716 isDef((i = i.innerHTML))717 ) {718 if (i !== elm.innerHTML) {719 /* istanbul ignore if */720 if (721 __DEV__ &&722 typeof console !== 'undefined' &&723 !hydrationBailed724 ) {725 hydrationBailed = true726 console.warn('Parent: ', elm)727 console.warn('server innerHTML: ', i)728 console.warn('client innerHTML: ', elm.innerHTML)729 }730 return false731 }732 } else {733 // iterate and compare children lists734 let childrenMatch = true735 let childNode = elm.firstChild736 for (let i = 0; i < children.length; i++) {737 if (738 !childNode ||739 !hydrate(childNode, children[i], insertedVnodeQueue, inVPre)740 ) {741 childrenMatch = false742 break743 }744 childNode = childNode.nextSibling745 }746 // if childNode is not null, it means the actual childNodes list is747 // longer than the virtual children list.748 if (!childrenMatch || childNode) {749 /* istanbul ignore if */750 if (751 __DEV__ &&752 typeof console !== 'undefined' &&753 !hydrationBailed754 ) {755 hydrationBailed = true756 console.warn('Parent: ', elm)757 console.warn(758 'Mismatching childNodes vs. VNodes: ',759 elm.childNodes,760 children761 )762 }763 return false764 }765 }766 }767 }768 if (isDef(data)) {769 let fullInvoke = false770 for (const key in data) {771 if (!isRenderedModule(key)) {772 fullInvoke = true773 invokeCreateHooks(vnode, insertedVnodeQueue)774 break775 }776 }777 if (!fullInvoke && data['class']) {778 // ensure collecting deps for deep class bindings for future updates779 traverse(data['class'])780 }781 }782 } else if (elm.data !== vnode.text) {783 elm.data = vnode.text784 }785 return true786 }787788 function assertNodeMatch(node, vnode, inVPre) {789 if (isDef(vnode.tag)) {790 return (791 vnode.tag.indexOf('vue-component') === 0 ||792 (!isUnknownElement(vnode, inVPre) &&793 vnode.tag.toLowerCase() ===794 (node.tagName && node.tagName.toLowerCase()))795 )796 } else {797 return node.nodeType === (vnode.isComment ? 8 : 3)798 }799 }800801 return function patch(oldVnode, vnode, hydrating, removeOnly) {802 if (isUndef(vnode)) {803 if (isDef(oldVnode)) invokeDestroyHook(oldVnode)804 return805 }806807 let isInitialPatch = false808 const insertedVnodeQueue: any[] = []809810 if (isUndef(oldVnode)) {811 // empty mount (likely as component), create new root element812 isInitialPatch = true813 createElm(vnode, insertedVnodeQueue)814 } else {815 const isRealElement = isDef(oldVnode.nodeType)816 if (!isRealElement && sameVnode(oldVnode, vnode)) {817 // patch existing root node818 patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly)819 } else {820 if (isRealElement) {821 // mounting to a real element822 // check if this is server-rendered content and if we can perform823 // a successful hydration.824 if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {825 oldVnode.removeAttribute(SSR_ATTR)826 hydrating = true827 }828 if (isTrue(hydrating)) {829 if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {830 invokeInsertHook(vnode, insertedVnodeQueue, true)831 return oldVnode832 } else if (__DEV__) {833 warn(834 'The client-side rendered virtual DOM tree is not matching ' +835 'server-rendered content. This is likely caused by incorrect ' +836 'HTML markup, for example nesting block-level elements inside ' +837 '<p>, or missing <tbody>. Bailing hydration and performing ' +838 'full client-side render.'839 )840 }841 }842 // either not server-rendered, or hydration failed.843 // create an empty node and replace it844 oldVnode = emptyNodeAt(oldVnode)845 }846847 // replacing existing element848 const oldElm = oldVnode.elm849 const parentElm = nodeOps.parentNode(oldElm)850851 // create new node852 createElm(853 vnode,854 insertedVnodeQueue,855 // extremely rare edge case: do not insert if old element is in a856 // leaving transition. Only happens when combining transition +857 // keep-alive + HOCs. (#4590)858 oldElm._leaveCb ? null : parentElm,859 nodeOps.nextSibling(oldElm)860 )861862 // update parent placeholder node element, recursively863 if (isDef(vnode.parent)) {864 let ancestor = vnode.parent865 const patchable = isPatchable(vnode)866 while (ancestor) {867 for (let i = 0; i < cbs.destroy.length; ++i) {868 cbs.destroy[i](ancestor)869 }870 ancestor.elm = vnode.elm871 if (patchable) {872 for (let i = 0; i < cbs.create.length; ++i) {873 cbs.create[i](emptyNode, ancestor)874 }875 // #6513876 // invoke insert hooks that may have been merged by create hooks.877 // e.g. for directives that uses the "inserted" hook.878 const insert = ancestor.data.hook.insert879 if (insert.merged) {880 // start at index 1 to avoid re-invoking component mounted hook881 // clone insert hooks to avoid being mutated during iteration.882 // e.g. for customed directives under transition group.883 const cloned = insert.fns.slice(1)884 for (let i = 0; i < cloned.length; i++) {885 cloned[i]()886 }887 }888 } else {889 registerRef(ancestor)890 }891 ancestor = ancestor.parent892 }893 }894895 // destroy old node896 if (isDef(parentElm)) {897 removeVnodes([oldVnode], 0, 0)898 } else if (isDef(oldVnode.tag)) {899 invokeDestroyHook(oldVnode)900 }901 }902 }903904 invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)905 return vnode.elm906 }907}
Findings
✓ No findings reported for this file.