fix(hmr): ensure static nodes inherit DOM element in hmr mode

fix #1156
This commit is contained in:
Evan You 2020-05-11 11:34:35 -04:00
parent a165d8293d
commit 66c5a556dc

View File

@ -10,7 +10,8 @@ import {
isSameVNodeType, isSameVNodeType,
Static, Static,
VNodeNormalizedRef, VNodeNormalizedRef,
VNodeHook VNodeHook,
isVNode
} from './vnode' } from './vnode'
import { import {
ComponentInternalInstance, ComponentInternalInstance,
@ -33,7 +34,8 @@ import {
ShapeFlags, ShapeFlags,
NOOP, NOOP,
hasOwn, hasOwn,
invokeArrayFns invokeArrayFns,
isArray
} from '@vue/shared' } from '@vue/shared'
import { import {
queueJob, queueJob,
@ -769,6 +771,9 @@ function baseCreateRenderer(
parentSuspense, parentSuspense,
areChildrenSVG areChildrenSVG
) )
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
traverseStaticChildren(n1, n2)
}
} else if (!optimized) { } else if (!optimized) {
// full diff // full diff
patchChildren( patchChildren(
@ -933,6 +938,9 @@ function baseCreateRenderer(
parentSuspense, parentSuspense,
isSVG isSVG
) )
if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
traverseStaticChildren(n1, n2)
}
} else { } else {
// keyed / unkeyed, or manual fragments. // keyed / unkeyed, or manual fragments.
// for keyed & unkeyed, since they are compiler generated from v-for, // for keyed & unkeyed, since they are compiler generated from v-for,
@ -1944,6 +1952,31 @@ function baseCreateRenderer(
} }
} }
/**
* #1156
* When a component is HMR-enabled, we need to make sure that all static nodes
* inside a block also inherit the DOM element from the previous tree so that
* HMR updates (which are full updates) can retrieve the element for patching.
*
* Dev only.
*/
const traverseStaticChildren = (n1: VNode, n2: VNode) => {
const ch1 = n1.children
const ch2 = n2.children
if (isArray(ch1) && isArray(ch2)) {
for (let i = 0; i < ch1.length; i++) {
const c1 = ch1[i]
const c2 = ch2[i]
if (isVNode(c1) && isVNode(c2) && !c2.dynamicChildren) {
if (c2.patchFlag <= 0) {
c2.el = c1.el
}
traverseStaticChildren(c1, c2)
}
}
}
}
const render: RootRenderFunction = (vnode, container) => { const render: RootRenderFunction = (vnode, container) => {
if (vnode == null) { if (vnode == null) {
if (container._vnode) { if (container._vnode) {