]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): fix data merge order for mixins/extends
authorEvan You <yyx990803@gmail.com>
Tue, 25 Aug 2020 01:30:04 +0000 (21:30 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 25 Aug 2020 01:30:04 +0000 (21:30 -0400)
fix #1953

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

index 95fed1d7fd270b3fd81ca52d6a6c90b64682264f..d61d46be363dc1bb5a46e25b24053ebec080d68f 100644 (file)
@@ -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 () => {
index bb7a32ecef2c13dcfa831467f813dbdf85ba3f9a..ff3927004ed57fda3e6bcd44f584a06ef4edb3c3 100644 (file)
@@ -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(