diff --git a/packages/core/src/componentOptions.ts b/packages/core/src/componentOptions.ts index ff3545f2..77fbb515 100644 --- a/packages/core/src/componentOptions.ts +++ b/packages/core/src/componentOptions.ts @@ -15,13 +15,17 @@ export interface ComponentClassOptions

{ computed?: ComponentComputedOptions watch?: ComponentWatchOptions displayName?: string + fromOptions?: boolean } export interface ComponentOptions< P = {}, D = {}, This = ComponentInstance -> extends ComponentClassOptions, APIMethods, LifecycleMethods { +> + extends ComponentClassOptions, + Partial>, + Partial { // TODO other options readonly [key: string]: any } @@ -161,10 +165,7 @@ export function mergeComponentOptions(to: any, from: any): ComponentOptions { if (isFunction(value) && isFunction(existing)) { if (key === 'data') { // for data we need to merge the returned value - // TODO: backwards compat requires recursive merge - res[key] = function() { - return Object.assign(existing.call(this), value.call(this)) - } + res[key] = mergeDataFn(existing, value) } else if (/^render|^errorCaptured/.test(key)) { // render, renderTracked, renderTriggered & errorCaptured // are never merged @@ -186,3 +187,11 @@ export function mergeComponentOptions(to: any, from: any): ComponentOptions { } return res } + +export function mergeDataFn(a: Function, b: Function): Function { + // TODO: backwards compat requires recursive merge, + // but maybe we should just warn if we detect clashing keys + return function() { + return Object.assign(a.call(this), b.call(this)) + } +} diff --git a/packages/core/src/componentState.ts b/packages/core/src/componentState.ts index 9a04b02e..8d838dbe 100644 --- a/packages/core/src/componentState.ts +++ b/packages/core/src/componentState.ts @@ -2,10 +2,15 @@ import { ComponentInstance } from './component' import { observable } from '@vue/observer' import { isReservedKey } from '@vue/shared' -export function initializeState(instance: ComponentInstance) { +export function initializeState( + instance: ComponentInstance, + shouldExtractInitializers: boolean +) { const { data } = instance.$options const rawData = (instance._rawData = (data ? data.call(instance) : {}) as any) - extractInitializers(instance, rawData) + if (shouldExtractInitializers) { + extractInitializers(instance, rawData) + } instance.$data = observable(rawData || {}) } diff --git a/packages/core/src/componentUtils.ts b/packages/core/src/componentUtils.ts index cad9bb75..54154a3c 100644 --- a/packages/core/src/componentUtils.ts +++ b/packages/core/src/componentUtils.ts @@ -45,7 +45,7 @@ export function createComponentInstance( $proxy, $options: { created, computed, watch } } = instance - initializeState(instance) + initializeState(instance, !Component.fromOptions) initializeComputed(instance, computed) initializeWatch(instance, watch) instance.$slots = currentVNode.slots || EMPTY_OBJ @@ -104,7 +104,7 @@ export function initializeComponentInstance(instance: ComponentInstance) { export function renderInstanceRoot(instance: ComponentInstance): VNode { let vnode try { - vnode = instance.$options.render.call( + vnode = instance.render.call( instance.$proxy, instance.$props, instance.$slots, @@ -209,6 +209,8 @@ export function createComponentClassFromOptions( ): ComponentClass { class AnonymousComponent extends Component { static options = options + // indicate this component was created from options + static fromOptions = true } const proto = AnonymousComponent.prototype as any for (const key in options) { diff --git a/packages/core/src/optional/mixins.ts b/packages/core/src/optional/mixins.ts index cf2b2c09..35fe31ea 100644 --- a/packages/core/src/optional/mixins.ts +++ b/packages/core/src/optional/mixins.ts @@ -3,7 +3,8 @@ import { createComponentClassFromOptions } from '../componentUtils' import { ComponentOptions, resolveComponentOptionsFromClass, - mergeComponentOptions + mergeComponentOptions, + mergeDataFn } from '../componentOptions' import { normalizePropsOptions } from '../componentProps' import { extractInitializers } from '../componentState' @@ -47,11 +48,7 @@ export function mixins(...args: any[]): any { return extractInitializers(new Class(this.$props)) } const { data } = mixin - mixin.data = data - ? function() { - return Object.assign(data.call(this), extractData.call(this)) - } - : extractData + mixin.data = data ? mergeDataFn(data, extractData) : extractData } else { mixin.props = normalizePropsOptions(mixin.props) }