]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hmr): ensure static nodes inherit DOM element in hmr mode
authorEvan You <yyx990803@gmail.com>
Mon, 11 May 2020 15:34:35 +0000 (11:34 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 11 May 2020 15:34:42 +0000 (11:34 -0400)
fix #1156

packages/runtime-core/src/renderer.ts

index de2139688552328de16792ba4476c06ce72774e6..40aa47f19daec172a0899089b35b75943fbb4b0b 100644 (file)
@@ -10,7 +10,8 @@ import {
   isSameVNodeType,
   Static,
   VNodeNormalizedRef,
-  VNodeHook
+  VNodeHook,
+  isVNode
 } from './vnode'
 import {
   ComponentInternalInstance,
@@ -33,7 +34,8 @@ import {
   ShapeFlags,
   NOOP,
   hasOwn,
-  invokeArrayFns
+  invokeArrayFns,
+  isArray
 } from '@vue/shared'
 import {
   queueJob,
@@ -769,6 +771,9 @@ function baseCreateRenderer(
         parentSuspense,
         areChildrenSVG
       )
+      if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
+        traverseStaticChildren(n1, n2)
+      }
     } else if (!optimized) {
       // full diff
       patchChildren(
@@ -933,6 +938,9 @@ function baseCreateRenderer(
           parentSuspense,
           isSVG
         )
+        if (__DEV__ && parentComponent && parentComponent.type.__hmrId) {
+          traverseStaticChildren(n1, n2)
+        }
       } else {
         // keyed / unkeyed, or manual fragments.
         // 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) => {
     if (vnode == null) {
       if (container._vnode) {