diff --git a/src/core/util/options.js b/src/core/util/options.js
index 99580f0443a..3a86509ae74 100644
--- a/src/core/util/options.js
+++ b/src/core/util/options.js
@@ -63,7 +63,7 @@ function mergeData (to: Object, from: ?Object): Object {
/**
* Data
*/
-strats.data = function (
+export function mergeDataOrFn (
parentVal: any,
childVal: any,
vm?: Component
@@ -73,15 +73,6 @@ strats.data = function (
if (!childVal) {
return parentVal
}
- if (typeof childVal !== 'function') {
- process.env.NODE_ENV !== 'production' && warn(
- 'The "data" option should be a function ' +
- 'that returns a per-instance value in component ' +
- 'definitions.',
- vm
- )
- return parentVal
- }
if (!parentVal) {
return childVal
}
@@ -92,7 +83,7 @@ strats.data = function (
// it has to be a function to pass previous merges.
return function mergedDataFn () {
return mergeData(
- childVal.call(this),
+ typeof childVal === 'function' ? childVal.call(this) : childVal,
parentVal.call(this)
)
}
@@ -114,6 +105,28 @@ strats.data = function (
}
}
+strats.data = function (
+ parentVal: any,
+ childVal: any,
+ vm?: Component
+): ?Function {
+ if (!vm) {
+ if (childVal && typeof childVal !== 'function') {
+ process.env.NODE_ENV !== 'production' && warn(
+ 'The "data" option should be a function ' +
+ 'that returns a per-instance value in component ' +
+ 'definitions.',
+ vm
+ )
+
+ return parentVal
+ }
+ return mergeDataOrFn.call(this, parentVal, childVal)
+ }
+
+ return mergeDataOrFn(parentVal, childVal, vm)
+}
+
/**
* Hooks and props are merged as arrays.
*/
@@ -191,6 +204,7 @@ strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object {
extend(ret, childVal)
return ret
}
+strats.provide = mergeDataOrFn
/**
* Default strategy.
diff --git a/test/unit/features/options/inject.spec.js b/test/unit/features/options/inject.spec.js
index c366918bd94..e3ba23d488c 100644
--- a/test/unit/features/options/inject.spec.js
+++ b/test/unit/features/options/inject.spec.js
@@ -298,4 +298,105 @@ describe('Options provide/inject', () => {
expect(`Injection "bar" not found`).not.toHaveBeenWarned()
expect(`Injection "baz" not found`).not.toHaveBeenWarned()
})
+
+ // Github issue #6008
+ it('should merge provide from mixins (objects)', () => {
+ const mixinA = { provide: { foo: 'foo' }}
+ const mixinB = { provide: { bar: 'bar' }}
+ const child = {
+ inject: ['foo', 'bar'],
+ template: ``,
+ created () {
+ injected = [this.foo, this.bar]
+ }
+ }
+ new Vue({
+ mixins: [mixinA, mixinB],
+ render (h) {
+ return h(child)
+ }
+ }).$mount()
+
+ expect(injected).toEqual(['foo', 'bar'])
+ })
+ it('should merge provide from mixins (functions)', () => {
+ const mixinA = { provide: () => ({ foo: 'foo' }) }
+ const mixinB = { provide: () => ({ bar: 'bar' }) }
+ const child = {
+ inject: ['foo', 'bar'],
+ template: ``,
+ created () {
+ injected = [this.foo, this.bar]
+ }
+ }
+ new Vue({
+ mixins: [mixinA, mixinB],
+ render (h) {
+ return h(child)
+ }
+ }).$mount()
+
+ expect(injected).toEqual(['foo', 'bar'])
+ })
+ it('should merge provide from mixins (mix of objects and functions)', () => {
+ const mixinA = { provide: { foo: 'foo' }}
+ const mixinB = { provide: () => ({ bar: 'bar' }) }
+ const mixinC = { provide: { baz: 'baz' }}
+ const mixinD = { provide: () => ({ bam: 'bam' }) }
+ const child = {
+ inject: ['foo', 'bar', 'baz', 'bam'],
+ template: ``,
+ created () {
+ injected = [this.foo, this.bar, this.baz, this.bam]
+ }
+ }
+ new Vue({
+ mixins: [mixinA, mixinB, mixinC, mixinD],
+ render (h) {
+ return h(child)
+ }
+ }).$mount()
+
+ expect(injected).toEqual(['foo', 'bar', 'baz', 'bam'])
+ })
+ it('should merge provide from mixins and override existing keys', () => {
+ const mixinA = { provide: { foo: 'foo' }}
+ const mixinB = { provide: { foo: 'bar' }}
+ const child = {
+ inject: ['foo'],
+ template: ``,
+ created () {
+ injected = [this.foo]
+ }
+ }
+ new Vue({
+ mixins: [mixinA, mixinB],
+ render (h) {
+ return h(child)
+ }
+ }).$mount()
+
+ expect(injected).toEqual(['bar'])
+ })
+ it('should merge provide when Vue.extend', () => {
+ const mixinA = { provide: () => ({ foo: 'foo' }) }
+ const child = {
+ inject: ['foo', 'bar'],
+ template: ``,
+ created () {
+ injected = [this.foo, this.bar]
+ }
+ }
+ const Ctor = Vue.extend({
+ mixins: [mixinA],
+ provide: { bar: 'bar' },
+ render (h) {
+ return h(child)
+ }
+ })
+
+ new Ctor().$mount()
+
+ expect(injected).toEqual(['foo', 'bar'])
+ })
})