From 6300551a05a70f47b8bac30292b01ddf9944fb8d Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Tue, 4 Jul 2017 06:47:34 +0530 Subject: [PATCH 1/4] test: Provide option not getting merged from mixins --- test/unit/features/options/inject.spec.js | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/unit/features/options/inject.spec.js b/test/unit/features/options/inject.spec.js index c366918bd94..efae36bb51a 100644 --- a/test/unit/features/options/inject.spec.js +++ b/test/unit/features/options/inject.spec.js @@ -298,4 +298,44 @@ 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', () => { + 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 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']) + }) }) From e23224bc50d597235f8d6b91dc1283d72af1e372 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Tue, 4 Jul 2017 08:14:22 +0530 Subject: [PATCH 2/4] fix: Merge strategy for provide option Fixes #6008 --- src/core/util/options.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/util/options.js b/src/core/util/options.js index 99580f0443a..11f56ba7c0f 100644 --- a/src/core/util/options.js +++ b/src/core/util/options.js @@ -183,6 +183,7 @@ strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object { strats.props = strats.methods = strats.inject = +strats.provide = strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object { if (!childVal) return Object.create(parentVal || null) if (!parentVal) return childVal From 6c7c3347764b90af9acec707008a9875ecf87f9b Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Tue, 4 Jul 2017 22:19:01 +0530 Subject: [PATCH 3/4] test: provide can be function or object --- test/unit/features/options/inject.spec.js | 63 ++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/test/unit/features/options/inject.spec.js b/test/unit/features/options/inject.spec.js index efae36bb51a..e3ba23d488c 100644 --- a/test/unit/features/options/inject.spec.js +++ b/test/unit/features/options/inject.spec.js @@ -300,7 +300,7 @@ describe('Options provide/inject', () => { }) // Github issue #6008 - it('should merge provide from mixins', () => { + it('should merge provide from mixins (objects)', () => { const mixinA = { provide: { foo: 'foo' }} const mixinB = { provide: { bar: 'bar' }} const child = { @@ -319,6 +319,46 @@ describe('Options provide/inject', () => { 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' }} @@ -338,4 +378,25 @@ describe('Options provide/inject', () => { 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']) + }) }) From 80bf22f37710121bc8ea93886dc6c371c1a5f2c4 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Wed, 5 Jul 2017 09:06:38 +0530 Subject: [PATCH 4/4] fix: use data merge stategy for provide option --- src/core/util/options.js | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/core/util/options.js b/src/core/util/options.js index 11f56ba7c0f..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. */ @@ -183,7 +196,6 @@ strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object { strats.props = strats.methods = strats.inject = -strats.provide = strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object { if (!childVal) return Object.create(parentVal || null) if (!parentVal) return childVal @@ -192,6 +204,7 @@ strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object { extend(ret, childVal) return ret } +strats.provide = mergeDataOrFn /** * Default strategy.