]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(hmr): always force full child component props update in HMR mode
authorEvan You <yyx990803@gmail.com>
Mon, 11 May 2020 18:17:35 +0000 (14:17 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 11 May 2020 18:17:35 +0000 (14:17 -0400)
packages/runtime-core/__tests__/hmr.spec.ts
packages/runtime-core/src/renderer.ts

index 8a141fe5f45d32065b7e4d0d32f8896dadb9b195..e23a222ff2a81ca45153d5d068260a4605d35369 100644 (file)
@@ -71,13 +71,13 @@ describe('hot module replacement', () => {
     expect(serializeInner(root)).toBe(`<div>11</div>`)
 
     // // Update text while preserving state
-    // rerender(
-    //   parentId,
-    //   compileToFunction(
-    //     `<div @click="count++">{{ count }}!<Child>{{ count }}</Child></div>`
-    //   )
-    // )
-    // expect(serializeInner(root)).toBe(`<div>1!1</div>`)
+    rerender(
+      parentId,
+      compileToFunction(
+        `<div @click="count++">{{ count }}!<Child>{{ count }}</Child></div>`
+      )
+    )
+    expect(serializeInner(root)).toBe(`<div>1!1</div>`)
 
     // Should force child update on slot content change
     rerender(
@@ -147,4 +147,75 @@ describe('hot module replacement', () => {
     expect(unmountSpy).toHaveBeenCalledTimes(1)
     expect(mountSpy).toHaveBeenCalledTimes(1)
   })
+
+  // #1156 - static nodes should retain DOM element reference across updates
+  // when HMR is active
+  test('static el reference', async () => {
+    const root = nodeOps.createElement('div')
+    const id = 'test-static-el'
+
+    const template = `<div>
+    <div>{{ count }}</div>
+    <button @click="count++">++</button>
+  </div>`
+
+    const Comp: ComponentOptions = {
+      __hmrId: id,
+      data() {
+        return { count: 0 }
+      },
+      render: compileToFunction(template)
+    }
+    createRecord(id, Comp)
+
+    render(h(Comp), root)
+    expect(serializeInner(root)).toBe(
+      `<div><div>0</div><button>++</button></div>`
+    )
+
+    // 1. click to trigger update
+    triggerEvent((root as any).children[0].children[1], 'click')
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      `<div><div>1</div><button>++</button></div>`
+    )
+
+    // 2. trigger HMR
+    rerender(
+      id,
+      compileToFunction(template.replace(`<button`, `<button class="foo"`))
+    )
+    expect(serializeInner(root)).toBe(
+      `<div><div>1</div><button class="foo">++</button></div>`
+    )
+  })
+
+  // #1157 - component should force full props update when HMR is active
+  test('force update child component w/ static props', () => {
+    const root = nodeOps.createElement('div')
+    const parentId = 'test2-parent'
+    const childId = 'test2-child'
+
+    const Child: ComponentOptions = {
+      __hmrId: childId,
+      props: {
+        msg: String
+      },
+      render: compileToFunction(`<div>{{ msg }}</div>`)
+    }
+    createRecord(childId, Child)
+
+    const Parent: ComponentOptions = {
+      __hmrId: parentId,
+      components: { Child },
+      render: compileToFunction(`<Child msg="foo" />`)
+    }
+    createRecord(parentId, Parent)
+
+    render(h(Parent), root)
+    expect(serializeInner(root)).toBe(`<div>foo</div>`)
+
+    rerender(parentId, compileToFunction(`<Child msg="bar" />`))
+    expect(serializeInner(root)).toBe(`<div>bar</div>`)
+  })
 })
index 956f3326914fef8c5f2c5858262d6d25e732c447..359648b531220d7b0e01bb992b0a9abf50497110 100644 (file)
@@ -1270,6 +1270,9 @@ function baseCreateRenderer(
     nextVNode: VNode,
     optimized: boolean
   ) => {
+    if (__DEV__ && instance.type.__hmrId) {
+      optimized = false
+    }
     nextVNode.component = instance
     const prevProps = instance.vnode.props
     instance.vnode = nextVNode