1414
1515import config from '../config'
1616import VNode from './vnode'
17- import { isPrimitive , _toString , warn } from '../util/index'
17+ import { makeMap , isPrimitive , _toString , warn } from '../util/index'
1818import { activeInstance } from '../instance/lifecycle'
1919import { registerRef } from './modules/ref'
2020
@@ -468,6 +468,11 @@ export function createPatchFunction (backend) {
468468 }
469469
470470 let bailed = false
471+ // list of modules that can skip create hook during hydration because they
472+ // are already rendered on the client or has no need for initialization
473+ const isRenderedModule = makeMap ( 'attrs,style,class,staticClass,staticStyle,key' )
474+
475+ // Note: this is a browser-only function so we can assume elms are DOM nodes.
471476 function hydrate ( elm , vnode , insertedVnodeQueue ) {
472477 if ( process . env . NODE_ENV !== 'production' ) {
473478 if ( ! assertNodeMatch ( elm , vnode ) ) {
@@ -486,36 +491,40 @@ export function createPatchFunction (backend) {
486491 }
487492 if ( isDef ( tag ) ) {
488493 if ( isDef ( children ) ) {
489- const childNodes = nodeOps . childNodes ( elm )
490494 // empty element, allow client to pick up and populate children
491- if ( ! childNodes . length ) {
495+ if ( ! elm . hasChildNodes ( ) ) {
492496 createChildren ( vnode , children , insertedVnodeQueue )
493497 } else {
494498 let childrenMatch = true
495- if ( childNodes . length !== children . length ) {
496- childrenMatch = false
497- } else {
498- for ( let i = 0 ; i < children . length ; i ++ ) {
499- if ( ! hydrate ( childNodes [ i ] , children [ i ] , insertedVnodeQueue ) ) {
500- childrenMatch = false
501- break
502- }
499+ let childNode = elm . firstChild
500+ for ( let i = 0 ; i < children . length ; i ++ ) {
501+ if ( ! childNode || ! hydrate ( childNode , children [ i ] , insertedVnodeQueue ) ) {
502+ childrenMatch = false
503+ break
503504 }
505+ childNode = childNode . nextSibling
504506 }
505- if ( ! childrenMatch ) {
507+ // if childNode is not null, it means the actual childNodes list is
508+ // longer than the virtual children list.
509+ if ( ! childrenMatch || childNode ) {
506510 if ( process . env . NODE_ENV !== 'production' &&
507511 typeof console !== 'undefined' &&
508512 ! bailed ) {
509513 bailed = true
510514 console . warn ( 'Parent: ' , elm )
511- console . warn ( 'Mismatching childNodes vs. VNodes: ' , childNodes , children )
515+ console . warn ( 'Mismatching childNodes vs. VNodes: ' , elm . childNodes , children )
512516 }
513517 return false
514518 }
515519 }
516520 }
517521 if ( isDef ( data ) ) {
518- invokeCreateHooks ( vnode , insertedVnodeQueue )
522+ for ( const key in data ) {
523+ if ( ! isRenderedModule ( key ) ) {
524+ invokeCreateHooks ( vnode , insertedVnodeQueue )
525+ break
526+ }
527+ }
519528 }
520529 }
521530 return true
@@ -525,7 +534,7 @@ export function createPatchFunction (backend) {
525534 if ( vnode . tag ) {
526535 return (
527536 vnode . tag . indexOf ( 'vue-component' ) === 0 ||
528- vnode . tag . toLowerCase ( ) === nodeOps . tagName ( node ) . toLowerCase ( )
537+ vnode . tag . toLowerCase ( ) === node . tagName . toLowerCase ( )
529538 )
530539 } else {
531540 return _toString ( vnode . text ) === node . data
0 commit comments