fix(hmr): always force full child component props update in HMR mode

This commit is contained in:
Evan You 2020-05-11 14:17:35 -04:00
parent 5b8883a846
commit 1b946c85df
2 changed files with 81 additions and 7 deletions

View File

@ -71,13 +71,13 @@ describe('hot module replacement', () => {
expect(serializeInner(root)).toBe(`<div>11</div>`) expect(serializeInner(root)).toBe(`<div>11</div>`)
// // Update text while preserving state // // Update text while preserving state
// rerender( rerender(
// parentId, parentId,
// compileToFunction( compileToFunction(
// `<div @click="count++">{{ count }}!<Child>{{ count }}</Child></div>` `<div @click="count++">{{ count }}!<Child>{{ count }}</Child></div>`
// ) )
// ) )
// expect(serializeInner(root)).toBe(`<div>1!1</div>`) expect(serializeInner(root)).toBe(`<div>1!1</div>`)
// Should force child update on slot content change // Should force child update on slot content change
rerender( rerender(
@ -147,4 +147,75 @@ describe('hot module replacement', () => {
expect(unmountSpy).toHaveBeenCalledTimes(1) expect(unmountSpy).toHaveBeenCalledTimes(1)
expect(mountSpy).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>`)
})
}) })

View File

@ -1270,6 +1270,9 @@ function baseCreateRenderer(
nextVNode: VNode, nextVNode: VNode,
optimized: boolean optimized: boolean
) => { ) => {
if (__DEV__ && instance.type.__hmrId) {
optimized = false
}
nextVNode.component = instance nextVNode.component = instance
const prevProps = instance.vnode.props const prevProps = instance.vnode.props
instance.vnode = nextVNode instance.vnode = nextVNode