From c15311cfe879aa98c06585d731d996fca7633421 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 24 Aug 2020 21:30:04 -0400 Subject: [PATCH] fix(runtime-core): fix data merge order for mixins/extends fix #1953 --- .../runtime-core/__tests__/apiOptions.spec.ts | 33 +++++++++++-------- packages/runtime-core/src/componentOptions.ts | 25 +++++++------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/runtime-core/__tests__/apiOptions.spec.ts b/packages/runtime-core/__tests__/apiOptions.spec.ts index 95fed1d7..d61d46be 100644 --- a/packages/runtime-core/__tests__/apiOptions.spec.ts +++ b/packages/runtime-core/__tests__/apiOptions.spec.ts @@ -446,7 +446,7 @@ describe('api: options', () => { calls.push('mixinA created') expect(this.a).toBe(1) expect(this.b).toBe(2) - expect(this.c).toBe(3) + expect(this.c).toBe(4) }, mounted() { calls.push('mixinA mounted') @@ -468,7 +468,7 @@ describe('api: options', () => { expect(this.a).toBe(1) expect(this.b).toBe(2) expect(this.bP).toBeUndefined() - expect(this.c).toBe(3) + expect(this.c).toBe(4) expect(this.cP1).toBeUndefined() }, mounted() { @@ -484,7 +484,8 @@ describe('api: options', () => { }, created() { calls.push('mixinC created') - expect(this.c).toBe(3) + // component data() should overwrite mixin field with same key + expect(this.c).toBe(4) expect(this.cP1).toBeUndefined() }, mounted() { @@ -498,6 +499,7 @@ describe('api: options', () => { mixins: [defineComponent(mixinA), defineComponent(mixinB), mixinC], data() { return { + c: 4, z: 4 } }, @@ -506,7 +508,7 @@ describe('api: options', () => { expect(this.a).toBe(1) expect(this.b).toBe(2) expect(this.bP).toBeUndefined() - expect(this.c).toBe(3) + expect(this.c).toBe(4) expect(this.cP2).toBeUndefined() expect(this.z).toBe(4) }, @@ -517,7 +519,7 @@ describe('api: options', () => { return `${this.a}${this.b}${this.c}` } }) - expect(renderToString(h(Comp))).toBe(`123`) + expect(renderToString(h(Comp))).toBe(`124`) expect(calls).toEqual([ 'mixinA created', 'mixinB created', @@ -546,7 +548,8 @@ describe('api: options', () => { const Base = { data() { return { - a: 1 + a: 1, + b: 1 } }, methods: { @@ -582,7 +585,8 @@ describe('api: options', () => { const Base = { data() { return { - a: 1 + a: 1, + x: 'base' } }, methods: { @@ -595,22 +599,23 @@ describe('api: options', () => { calls.push('base') } } - const Base2 = { + const Mixin = { data() { return { - b: true + b: true, + x: 'mixin' } }, mounted(this: any) { expect(this.a).toBe(1) expect(this.b).toBeTruthy() expect(this.c).toBe(2) - calls.push('base2') + calls.push('mixin') } } const Comp = defineComponent({ extends: defineComponent(Base), - mixins: [defineComponent(Base2)], + mixins: [defineComponent(Mixin)], data() { return { c: 2 @@ -620,12 +625,12 @@ describe('api: options', () => { calls.push('comp') }, render() { - return `${this.a}${this.b}${this.c}` + return `${this.a}${this.b}${this.c}${this.x}` } }) - expect(renderToString(h(Comp))).toBe(`1true2`) - expect(calls).toEqual(['base', 'base2', 'comp']) + expect(renderToString(h(Comp))).toBe(`1true2mixin`) + expect(calls).toEqual(['base', 'mixin', 'comp']) }) test('accessing setup() state from options', async () => { diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index bb7a32ec..ff392700 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -485,24 +485,13 @@ export function applyOptions( } } - if (dataOptions) { - if (__DEV__ && !isFunction(dataOptions)) { - warn( - `The data option must be a function. ` + - `Plain object usage is no longer supported.` - ) - } - - if (asMixin) { - deferredData.push(dataOptions as DataFn) - } else { - resolveData(instance, dataOptions, publicThis) - } - } if (!asMixin) { if (deferredData.length) { deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis)) } + if (dataOptions) { + resolveData(instance, dataOptions, publicThis) + } if (__DEV__) { const rawData = toRaw(instance.data) for (const key in rawData) { @@ -518,6 +507,8 @@ export function applyOptions( } } } + } else if (dataOptions) { + deferredData.push(dataOptions as DataFn) } if (computedOptions) { @@ -666,6 +657,12 @@ function resolveData( dataFn: DataFn, publicThis: ComponentPublicInstance ) { + if (__DEV__ && !isFunction(dataFn)) { + warn( + `The data option must be a function. ` + + `Plain object usage is no longer supported.` + ) + } const data = dataFn.call(publicThis, publicThis) if (__DEV__ && isPromise(data)) { warn(