fix(runtime-core): align option merge behavior with Vue 2
fix #3566, #2791
This commit is contained in:
@@ -531,7 +531,10 @@ const seenConfigObjects = /*#__PURE__*/ new WeakSet<CompatConfig>()
|
||||
const warnedInvalidKeys: Record<string, boolean> = {}
|
||||
|
||||
// dev only
|
||||
export function validateCompatConfig(config: CompatConfig) {
|
||||
export function validateCompatConfig(
|
||||
config: CompatConfig,
|
||||
instance?: ComponentInternalInstance
|
||||
) {
|
||||
if (seenConfigObjects.has(config)) {
|
||||
return
|
||||
}
|
||||
@@ -558,6 +561,14 @@ export function validateCompatConfig(config: CompatConfig) {
|
||||
warnedInvalidKeys[key] = true
|
||||
}
|
||||
}
|
||||
|
||||
if (instance && config[DeprecationTypes.OPTIONS_DATA_MERGE] != null) {
|
||||
warn(
|
||||
`Deprecation config "${
|
||||
DeprecationTypes.OPTIONS_DATA_MERGE
|
||||
}" can only be configured globally.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function getCompatConfigForKey(
|
||||
|
||||
@@ -1,39 +1,16 @@
|
||||
import { isFunction, isPlainObject } from '@vue/shared'
|
||||
import { ComponentInternalInstance } from '../component'
|
||||
import { ComponentPublicInstance } from '../componentPublicInstance'
|
||||
import { isPlainObject } from '@vue/shared'
|
||||
import { DeprecationTypes, warnDeprecation } from './compatConfig'
|
||||
|
||||
export function deepMergeData(
|
||||
to: any,
|
||||
from: any,
|
||||
instance: ComponentInternalInstance
|
||||
) {
|
||||
export function deepMergeData(to: any, from: any) {
|
||||
for (const key in from) {
|
||||
const toVal = to[key]
|
||||
const fromVal = from[key]
|
||||
if (key in to && isPlainObject(toVal) && isPlainObject(fromVal)) {
|
||||
__DEV__ &&
|
||||
warnDeprecation(DeprecationTypes.OPTIONS_DATA_MERGE, instance, key)
|
||||
deepMergeData(toVal, fromVal, instance)
|
||||
__DEV__ && warnDeprecation(DeprecationTypes.OPTIONS_DATA_MERGE, null, key)
|
||||
deepMergeData(toVal, fromVal)
|
||||
} else {
|
||||
to[key] = fromVal
|
||||
}
|
||||
}
|
||||
return to
|
||||
}
|
||||
|
||||
export function mergeDataOption(to: any, from: any) {
|
||||
if (!from) {
|
||||
return to
|
||||
}
|
||||
if (!to) {
|
||||
return from
|
||||
}
|
||||
return function mergedDataFn(this: ComponentPublicInstance) {
|
||||
return deepMergeData(
|
||||
isFunction(to) ? to.call(this, this) : to,
|
||||
isFunction(from) ? from.call(this, this) : from,
|
||||
this.$
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,11 @@ import {
|
||||
isRuntimeOnly,
|
||||
setupComponent
|
||||
} from '../component'
|
||||
import { RenderFunction, mergeOptions } from '../componentOptions'
|
||||
import {
|
||||
RenderFunction,
|
||||
mergeOptions,
|
||||
internalOptionMergeStrats
|
||||
} from '../componentOptions'
|
||||
import { ComponentPublicInstance } from '../componentPublicInstance'
|
||||
import { devtoolsInitApp, devtoolsUnmountApp } from '../devtools'
|
||||
import { Directive } from '../directives'
|
||||
@@ -43,8 +47,7 @@ import { version } from '..'
|
||||
import {
|
||||
installLegacyConfigWarnings,
|
||||
installLegacyOptionMergeStrats,
|
||||
LegacyConfig,
|
||||
legacyOptionMergeStrats
|
||||
LegacyConfig
|
||||
} from './globalConfig'
|
||||
import { LegacyDirective } from './customDirective'
|
||||
import {
|
||||
@@ -231,8 +234,7 @@ export function createCompatVue(
|
||||
mergeOptions(
|
||||
extend({}, SubVue.options),
|
||||
inlineOptions,
|
||||
null,
|
||||
legacyOptionMergeStrats as any
|
||||
internalOptionMergeStrats as any
|
||||
),
|
||||
SubVue
|
||||
)
|
||||
@@ -257,8 +259,7 @@ export function createCompatVue(
|
||||
SubVue.options = mergeOptions(
|
||||
mergeBase,
|
||||
extendOptions,
|
||||
null,
|
||||
legacyOptionMergeStrats as any
|
||||
internalOptionMergeStrats as any
|
||||
)
|
||||
|
||||
SubVue.options._base = SubVue
|
||||
@@ -305,8 +306,7 @@ export function createCompatVue(
|
||||
mergeOptions(
|
||||
parent,
|
||||
child,
|
||||
vm && vm.$,
|
||||
vm ? undefined : (legacyOptionMergeStrats as any)
|
||||
vm ? undefined : (internalOptionMergeStrats as any)
|
||||
),
|
||||
defineReactive
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { extend, isArray } from '@vue/shared'
|
||||
import { AppConfig } from '../apiCreateApp'
|
||||
import { mergeDataOption } from './data'
|
||||
import {
|
||||
DeprecationTypes,
|
||||
softAssertCompatEnabled,
|
||||
warnDeprecation
|
||||
} from './compatConfig'
|
||||
import { isCopyingConfig } from './global'
|
||||
import { internalOptionMergeStrats } from '../componentOptions'
|
||||
|
||||
// legacy config warnings
|
||||
export type LegacyConfig = {
|
||||
@@ -70,60 +69,16 @@ export function installLegacyOptionMergeStrats(config: AppConfig) {
|
||||
return target[key]
|
||||
}
|
||||
if (
|
||||
key in legacyOptionMergeStrats &&
|
||||
key in internalOptionMergeStrats &&
|
||||
softAssertCompatEnabled(
|
||||
DeprecationTypes.CONFIG_OPTION_MERGE_STRATS,
|
||||
null
|
||||
)
|
||||
) {
|
||||
return legacyOptionMergeStrats[
|
||||
key as keyof typeof legacyOptionMergeStrats
|
||||
return internalOptionMergeStrats[
|
||||
key as keyof typeof internalOptionMergeStrats
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const legacyOptionMergeStrats = {
|
||||
data: mergeDataOption,
|
||||
beforeCreate: mergeHook,
|
||||
created: mergeHook,
|
||||
beforeMount: mergeHook,
|
||||
mounted: mergeHook,
|
||||
beforeUpdate: mergeHook,
|
||||
updated: mergeHook,
|
||||
beforeDestroy: mergeHook,
|
||||
destroyed: mergeHook,
|
||||
activated: mergeHook,
|
||||
deactivated: mergeHook,
|
||||
errorCaptured: mergeHook,
|
||||
serverPrefetch: mergeHook,
|
||||
// assets
|
||||
components: mergeObjectOptions,
|
||||
directives: mergeObjectOptions,
|
||||
filters: mergeObjectOptions,
|
||||
// objects
|
||||
props: mergeObjectOptions,
|
||||
methods: mergeObjectOptions,
|
||||
inject: mergeObjectOptions,
|
||||
computed: mergeObjectOptions,
|
||||
// watch has special merge behavior in v2, but isn't actually needed in v3.
|
||||
// since we are only exposing these for compat and nobody should be relying
|
||||
// on the watch-specific behavior, just expose the object merge strat.
|
||||
watch: mergeObjectOptions
|
||||
}
|
||||
|
||||
function toArray(target: any) {
|
||||
return isArray(target) ? target : target ? [target] : []
|
||||
}
|
||||
|
||||
function mergeHook(
|
||||
to: Function[] | Function | undefined,
|
||||
from: Function | Function[]
|
||||
) {
|
||||
return Array.from(new Set([...toArray(to), ...toArray(from)]))
|
||||
}
|
||||
|
||||
function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
|
||||
return to ? extend(extend(Object.create(null), to), from) : from
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user