diff --git a/packages/runtime-core/__tests__/hmr.spec.ts b/packages/runtime-core/__tests__/hmr.spec.ts index 4f1a5e5ddb6..a5d0d67d51d 100644 --- a/packages/runtime-core/__tests__/hmr.spec.ts +++ b/packages/runtime-core/__tests__/hmr.spec.ts @@ -11,12 +11,13 @@ import { nextTick } from '@vue/runtime-test' import * as runtimeTest from '@vue/runtime-test' +import { registerRuntimeCompiler, createApp } from '@vue/runtime-test' import { baseCompile } from '@vue/compiler-core' declare var __VUE_HMR_RUNTIME__: HMRRuntime const { createRecord, rerender, reload } = __VUE_HMR_RUNTIME__ -runtimeTest.registerRuntimeCompiler(compileToFunction) +registerRuntimeCompiler(compileToFunction) function compileToFunction(template: string) { const { code } = baseCompile(template) @@ -395,4 +396,43 @@ describe('hot module replacement', () => { `
1
2
` ) }) + + // #4174 + test('with global mixins', async () => { + const childId = 'hmr-global-mixin' + const createSpy1 = jest.fn() + const createSpy2 = jest.fn() + + const Child: ComponentOptions = { + __hmrId: childId, + created: createSpy1, + render() { + return h('div') + } + } + createRecord(childId, Child) + + const Parent: ComponentOptions = { + render: () => h(Child) + } + + const app = createApp(Parent) + app.mixin({}) + + const root = nodeOps.createElement('div') + app.mount(root) + expect(createSpy1).toHaveBeenCalledTimes(1) + expect(createSpy2).toHaveBeenCalledTimes(0) + + reload(childId, { + __hmrId: childId, + created: createSpy2, + render() { + return h('div') + } + }) + await nextTick() + expect(createSpy1).toHaveBeenCalledTimes(1) + expect(createSpy2).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/runtime-core/src/hmr.ts b/packages/runtime-core/src/hmr.ts index efa10f4dc98..2021e4f9aa7 100644 --- a/packages/runtime-core/src/hmr.ts +++ b/packages/runtime-core/src/hmr.ts @@ -130,6 +130,9 @@ function reload(id: string, newComp: ComponentOptions | ClassComponent) { } Array.from(instances).forEach(instance => { + // invalidate options resolution cache + instance.appContext.optionsCache.delete(instance.type as any) + if (instance.parent) { // 4. Force the parent instance to re-render. This will cause all updated // components to be unmounted and re-mounted. Queue the update so that we