Skip to content

Commit c15311c

Browse files
committed
fix(runtime-core): fix data merge order for mixins/extends
fix #1953
1 parent b742384 commit c15311c

File tree

2 files changed

+30
-28
lines changed

2 files changed

+30
-28
lines changed

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

+19-14
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ describe('api: options', () => {
446446
calls.push('mixinA created')
447447
expect(this.a).toBe(1)
448448
expect(this.b).toBe(2)
449-
expect(this.c).toBe(3)
449+
expect(this.c).toBe(4)
450450
},
451451
mounted() {
452452
calls.push('mixinA mounted')
@@ -468,7 +468,7 @@ describe('api: options', () => {
468468
expect(this.a).toBe(1)
469469
expect(this.b).toBe(2)
470470
expect(this.bP).toBeUndefined()
471-
expect(this.c).toBe(3)
471+
expect(this.c).toBe(4)
472472
expect(this.cP1).toBeUndefined()
473473
},
474474
mounted() {
@@ -484,7 +484,8 @@ describe('api: options', () => {
484484
},
485485
created() {
486486
calls.push('mixinC created')
487-
expect(this.c).toBe(3)
487+
// component data() should overwrite mixin field with same key
488+
expect(this.c).toBe(4)
488489
expect(this.cP1).toBeUndefined()
489490
},
490491
mounted() {
@@ -498,6 +499,7 @@ describe('api: options', () => {
498499
mixins: [defineComponent(mixinA), defineComponent(mixinB), mixinC],
499500
data() {
500501
return {
502+
c: 4,
501503
z: 4
502504
}
503505
},
@@ -506,7 +508,7 @@ describe('api: options', () => {
506508
expect(this.a).toBe(1)
507509
expect(this.b).toBe(2)
508510
expect(this.bP).toBeUndefined()
509-
expect(this.c).toBe(3)
511+
expect(this.c).toBe(4)
510512
expect(this.cP2).toBeUndefined()
511513
expect(this.z).toBe(4)
512514
},
@@ -517,7 +519,7 @@ describe('api: options', () => {
517519
return `${this.a}${this.b}${this.c}`
518520
}
519521
})
520-
expect(renderToString(h(Comp))).toBe(`123`)
522+
expect(renderToString(h(Comp))).toBe(`124`)
521523
expect(calls).toEqual([
522524
'mixinA created',
523525
'mixinB created',
@@ -546,7 +548,8 @@ describe('api: options', () => {
546548
const Base = {
547549
data() {
548550
return {
549-
a: 1
551+
a: 1,
552+
b: 1
550553
}
551554
},
552555
methods: {
@@ -582,7 +585,8 @@ describe('api: options', () => {
582585
const Base = {
583586
data() {
584587
return {
585-
a: 1
588+
a: 1,
589+
x: 'base'
586590
}
587591
},
588592
methods: {
@@ -595,22 +599,23 @@ describe('api: options', () => {
595599
calls.push('base')
596600
}
597601
}
598-
const Base2 = {
602+
const Mixin = {
599603
data() {
600604
return {
601-
b: true
605+
b: true,
606+
x: 'mixin'
602607
}
603608
},
604609
mounted(this: any) {
605610
expect(this.a).toBe(1)
606611
expect(this.b).toBeTruthy()
607612
expect(this.c).toBe(2)
608-
calls.push('base2')
613+
calls.push('mixin')
609614
}
610615
}
611616
const Comp = defineComponent({
612617
extends: defineComponent(Base),
613-
mixins: [defineComponent(Base2)],
618+
mixins: [defineComponent(Mixin)],
614619
data() {
615620
return {
616621
c: 2
@@ -620,12 +625,12 @@ describe('api: options', () => {
620625
calls.push('comp')
621626
},
622627
render() {
623-
return `${this.a}${this.b}${this.c}`
628+
return `${this.a}${this.b}${this.c}${this.x}`
624629
}
625630
})
626631

627-
expect(renderToString(h(Comp))).toBe(`1true2`)
628-
expect(calls).toEqual(['base', 'base2', 'comp'])
632+
expect(renderToString(h(Comp))).toBe(`1true2mixin`)
633+
expect(calls).toEqual(['base', 'mixin', 'comp'])
629634
})
630635

631636
test('accessing setup() state from options', async () => {

packages/runtime-core/src/componentOptions.ts

+11-14
Original file line numberDiff line numberDiff line change
@@ -485,24 +485,13 @@ export function applyOptions(
485485
}
486486
}
487487

488-
if (dataOptions) {
489-
if (__DEV__ && !isFunction(dataOptions)) {
490-
warn(
491-
`The data option must be a function. ` +
492-
`Plain object usage is no longer supported.`
493-
)
494-
}
495-
496-
if (asMixin) {
497-
deferredData.push(dataOptions as DataFn)
498-
} else {
499-
resolveData(instance, dataOptions, publicThis)
500-
}
501-
}
502488
if (!asMixin) {
503489
if (deferredData.length) {
504490
deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis))
505491
}
492+
if (dataOptions) {
493+
resolveData(instance, dataOptions, publicThis)
494+
}
506495
if (__DEV__) {
507496
const rawData = toRaw(instance.data)
508497
for (const key in rawData) {
@@ -518,6 +507,8 @@ export function applyOptions(
518507
}
519508
}
520509
}
510+
} else if (dataOptions) {
511+
deferredData.push(dataOptions as DataFn)
521512
}
522513

523514
if (computedOptions) {
@@ -666,6 +657,12 @@ function resolveData(
666657
dataFn: DataFn,
667658
publicThis: ComponentPublicInstance
668659
) {
660+
if (__DEV__ && !isFunction(dataFn)) {
661+
warn(
662+
`The data option must be a function. ` +
663+
`Plain object usage is no longer supported.`
664+
)
665+
}
669666
const data = dataFn.call(publicThis, publicThis)
670667
if (__DEV__ && isPromise(data)) {
671668
warn(

0 commit comments

Comments
 (0)