Skip to content

Commit

Permalink
fix bug vuejs#5073 HMR on keepalive components caused error
Browse files Browse the repository at this point in the history
  • Loading branch information
Math-chen committed Dec 24, 2021
1 parent a273e88 commit b03908f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
57 changes: 57 additions & 0 deletions packages/runtime-core/__tests__/hmr.spec.ts
Expand Up @@ -469,4 +469,61 @@ describe('hot module replacement', () => {
render(h(Foo), root)
expect(serializeInner(root)).toBe('bar')
})

test('reload for keep-alive instance',async () => {
const parentId = 'keep-alive-parent-reload'
const barId = 'keep-alive-bar-reload'
const fooId = 'keep-alive-foo-reload'
const root = nodeOps.createElement('div')
const Bar: ComponentOptions = {
__hmrId: barId,
render: compileToFunction(`<div>bar</div>`)
}
const Foo: ComponentOptions = {
__hmrId: fooId,
render: compileToFunction(`<div>foo</div>`)
}
const Parent: ComponentOptions = {
__hmrId: parentId,
data() {
return {
value: 'bar'
}
},
components: {
foo: Foo,
bar: Bar
},
render: compileToFunction(`
<button @click="value = value === 'bar'?'foo':'bar'">switch</button>
<keep-alive>
<component :is="value"></component>
</keep-alive>
`)
}
createRecord(parentId, Parent)
createRecord(barId, Bar)
createRecord(fooId, Foo)
const app = createApp(Parent)
app.mount(root)
expect(serializeInner(root)).toBe('<button>switch</button><div>bar</div>')
reload(barId, {
__hmrId: barId,
render: compileToFunction(`<div>bar1</div>`)
})
await nextTick()
expect(serializeInner(root)).toBe('<button>switch</button><div>bar1</div>')
triggerEvent(root.children[1] as TestElement, 'click')
await nextTick()
expect(serializeInner(root)).toBe('<button>switch</button><div>foo</div>')
triggerEvent(root.children[1] as TestElement, 'click')
await nextTick()
expect(serializeInner(root)).toBe('<button>switch</button><div>bar1</div>')
reload(barId, {
__hmrId: barId,
render: compileToFunction(`<div>bar2</div>`)
})
await nextTick()
expect(serializeInner(root)).toBe('<button>switch</button><div>bar2</div>')
})
})
9 changes: 9 additions & 0 deletions packages/runtime-core/src/components/KeepAlive.ts
Expand Up @@ -42,6 +42,7 @@ import { setTransitionHooks } from './BaseTransition'
import { ComponentRenderContext } from '../componentPublicInstance'
import { devtoolsComponentAdded } from '../devtools'
import { isAsyncWrapper } from '../apiAsyncComponent'
import { registerHMR, unregisterHMR } from '../hmr'

type MatchPattern = string | RegExp | string[] | RegExp[]

Expand Down Expand Up @@ -121,6 +122,9 @@ const KeepAliveImpl: ComponentOptions = {

sharedContext.activate = (vnode, container, anchor, isSVG, optimized) => {
const instance = vnode.component!
if(__DEV__ && instance.type.__hmrId) {
registerHMR(instance);
}
move(vnode, container, anchor, MoveType.ENTER, parentSuspense)
// in case props have changed
patch(
Expand Down Expand Up @@ -153,6 +157,9 @@ const KeepAliveImpl: ComponentOptions = {

sharedContext.deactivate = (vnode: VNode) => {
const instance = vnode.component!
if(__DEV__ && instance.type.__hmrId) {
unregisterHMR(instance);
}
move(vnode, storageContainer, null, MoveType.LEAVE, parentSuspense)
queuePostRenderEffect(() => {
if (instance.da) {
Expand All @@ -171,6 +178,8 @@ const KeepAliveImpl: ComponentOptions = {
}
}

sharedContext.pruneCacheEntry = pruneCacheEntry

function unmount(vnode: VNode) {
// reset the shapeFlag so it can be properly unmounted
resetShapeFlag(vnode)
Expand Down
7 changes: 7 additions & 0 deletions packages/runtime-core/src/hmr.ts
Expand Up @@ -112,6 +112,13 @@ function reload(id: string, newComp: HMRComponent) {
for (const instance of instances) {
const oldComp = normalizeClassComponent(instance.type as HMRComponent)

//#5073 # need to cleanup the cache in keep-alive and reset the shapeFlag
if(instance.parent && (instance.parent.type as ComponentOptions).__isKeepAlive) {
const vnode = instance.vnode
const key = vnode.key == null ? vnode.type : vnode.key;
(instance.parent.ctx as any).pruneCacheEntry(key)
}

if (!hmrDirtyComponents.has(oldComp)) {
// 1. Update existing comp definition to match new one
if (oldComp !== record.initialDef) {
Expand Down

0 comments on commit b03908f

Please sign in to comment.