From b0aa234e5e7a611c018de68bc31e0cf55518d5ce Mon Sep 17 00:00:00 2001 From: skirtle <65301168+skirtles-code@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:56:37 +0100 Subject: [PATCH] fix(runtime-core): use separate prop caches for components and mixins (#11350) Co-authored-by: Red Huang close #7998 --- .../__tests__/componentProps.spec.ts | 90 +++++++++++++++++++ packages/runtime-core/src/componentProps.ts | 5 +- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/componentProps.spec.ts b/packages/runtime-core/__tests__/componentProps.spec.ts index 8244580005b..8c9c38b3c1f 100644 --- a/packages/runtime-core/__tests__/componentProps.spec.ts +++ b/packages/runtime-core/__tests__/componentProps.spec.ts @@ -538,6 +538,96 @@ describe('component props', () => { expect(renderProxy.$props).toMatchObject(props) }) + test('merging props from global mixins and extends', () => { + let renderProxy: any + let extendedRenderProxy: any + + const defaultProp = ' from global' + const props = { + globalProp: { + type: String, + default: defaultProp, + }, + } + const globalMixin = { + props, + } + const Comp = { + render(this: any) { + renderProxy = this + return h('div', ['Comp', this.globalProp]) + }, + } + const ExtendedComp = { + extends: Comp, + render(this: any) { + extendedRenderProxy = this + return h('div', ['ExtendedComp', this.globalProp]) + }, + } + + const app = createApp( + { + render: () => [h(ExtendedComp), h(Comp)], + }, + {}, + ) + app.mixin(globalMixin) + + const root = nodeOps.createElement('div') + app.mount(root) + + expect(serializeInner(root)).toMatch( + `
ExtendedComp from global
Comp from global
`, + ) + expect(renderProxy.$props).toMatchObject({ globalProp: defaultProp }) + expect(extendedRenderProxy.$props).toMatchObject({ + globalProp: defaultProp, + }) + }) + + test('merging props for a component that is also used as a mixin', () => { + const CompA = { + render(this: any) { + return this.foo + }, + } + + const mixin = { + props: { + foo: { + default: 'from mixin', + }, + }, + } + + const CompB = { + mixins: [mixin, CompA], + render(this: any) { + return this.foo + }, + } + + const app = createApp({ + render() { + return [h(CompA), ', ', h(CompB)] + }, + }) + + app.mixin({ + props: { + foo: { + default: 'from global mixin', + }, + }, + }) + + const root = nodeOps.createElement('div') + app.mount(root) + + expect(serializeInner(root)).toMatch(`from global mixin, from mixin`) + }) + test('props type support BigInt', () => { const Comp = { props: { diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 5a4292b6f36..9d7b7f0e4a5 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -496,12 +496,15 @@ function resolvePropValue( return value } +const mixinPropsCache = new WeakMap() + export function normalizePropsOptions( comp: ConcreteComponent, appContext: AppContext, asMixin = false, ): NormalizedPropsOptions { - const cache = appContext.propsCache + const cache = + __FEATURE_OPTIONS_API__ && asMixin ? mixinPropsCache : appContext.propsCache const cached = cache.get(comp) if (cached) { return cached