Skip to content

Commit c508fc0

Browse files
committed
fix(runtime-core): use separate emits caches for components and mixins
1 parent 770ea67 commit c508fc0

File tree

2 files changed

+117
-1
lines changed

2 files changed

+117
-1
lines changed

packages/runtime-core/__tests__/componentEmits.spec.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import {
55
type ComponentPublicInstance,
6+
createApp,
67
defineComponent,
78
h,
89
nextTick,
@@ -598,4 +599,117 @@ describe('component: emit', () => {
598599
render(h(ComponentC), el)
599600
expect(renderFn).toHaveBeenCalledTimes(1)
600601
})
602+
test('merging emits for a component that is also used as a mixin', () => {
603+
const render = () => h('div')
604+
const CompA = {
605+
render,
606+
}
607+
const validateByMixin = vi.fn(() => true)
608+
const validateByGlobalMixin = vi.fn(() => true)
609+
610+
const mixin = {
611+
emits: {
612+
one: validateByMixin,
613+
},
614+
}
615+
616+
const CompB = defineComponent({
617+
mixins: [mixin, CompA],
618+
created(this) {
619+
this.$emit('one', 1)
620+
},
621+
render,
622+
})
623+
624+
const app = createApp({
625+
render() {
626+
return [h(CompA), h(CompB)]
627+
},
628+
})
629+
630+
app.mixin({
631+
emits: {
632+
one: validateByGlobalMixin,
633+
two: null,
634+
},
635+
})
636+
637+
const root = nodeOps.createElement('div')
638+
app.mount(root)
639+
expect(validateByMixin).toHaveBeenCalledTimes(1)
640+
expect(validateByGlobalMixin).not.toHaveBeenCalled()
641+
})
642+
})
643+
644+
test('merging emits for a component that is also used as a mixin', () => {
645+
const render = () => h('div')
646+
const CompA = {
647+
render,
648+
}
649+
650+
const mixin = {
651+
emits: {
652+
one: (arg: number) => arg === 1,
653+
},
654+
}
655+
656+
const CompB = {
657+
mixins: [mixin, CompA],
658+
created(this: ComponentPublicInstance) {
659+
this.$emit('one', 1)
660+
},
661+
render,
662+
}
663+
664+
const app = createApp({
665+
render() {
666+
return [h(CompA), ', ', h(CompB)]
667+
},
668+
})
669+
670+
app.mixin({
671+
emits: {
672+
one: (arg: number) => arg === 0,
673+
two: null,
674+
},
675+
})
676+
677+
const root = nodeOps.createElement('div')
678+
app.mount(root)
679+
expect(`event validation failed for event "one"`).not.toHaveBeenWarned()
680+
})
681+
682+
test('merging props from global mixins and extends', () => {
683+
let renderProxy: any
684+
let extendedRenderProxy: any
685+
const render = () => h('div')
686+
const Comp = {
687+
mounted(this: ComponentPublicInstance) {
688+
renderProxy = this
689+
},
690+
render,
691+
}
692+
693+
const ExtendedComp = {
694+
extends: Comp,
695+
mounted(this: ComponentPublicInstance) {
696+
extendedRenderProxy = this
697+
},
698+
render,
699+
}
700+
701+
const app = createApp({
702+
render: () => [h(ExtendedComp), h(Comp)],
703+
})
704+
705+
const emits = {
706+
one: (arg: number) => arg === 0,
707+
two: (arg: number) => arg === 0,
708+
}
709+
app.mixin({ emits })
710+
711+
const root = nodeOps.createElement('div')
712+
app.mount(root)
713+
expect(renderProxy._.emitsOptions).toMatchObject(emits)
714+
expect(extendedRenderProxy._.emitsOptions).toMatchObject(emits)
601715
})

packages/runtime-core/src/componentEmits.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,14 @@ export function emit(
228228
}
229229
}
230230

231+
const mixinEmitsCache = new WeakMap<ConcreteComponent, ObjectEmitsOptions>()
231232
export function normalizeEmitsOptions(
232233
comp: ConcreteComponent,
233234
appContext: AppContext,
234235
asMixin = false,
235236
): ObjectEmitsOptions | null {
236-
const cache = appContext.emitsCache
237+
const cache =
238+
__FEATURE_OPTIONS_API__ && asMixin ? mixinEmitsCache : appContext.emitsCache
237239
const cached = cache.get(comp)
238240
if (cached !== undefined) {
239241
return cached

0 commit comments

Comments
 (0)