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', () => {
`
`
)
})
+
+ // #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