wip: data option compat

This commit is contained in:
Evan You 2021-04-06 09:31:47 -04:00
parent 53b8127a9c
commit d0da0028f2
5 changed files with 53 additions and 10 deletions

View File

@ -0,0 +1,15 @@
import { isPlainObject } from '@vue/shared'
import { DeprecationTypes, warnDeprecation } from './deprecations'
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, key)
deepMergeData(toVal, fromVal)
} else {
to[key] = fromVal
}
}
}

View File

@ -1,4 +1,5 @@
import { isRuntimeOnly } from '../component'
import { warn } from '../warning'
export const enum DeprecationTypes {
CONFIG_SILENT,
@ -16,11 +17,14 @@ export const enum DeprecationTypes {
INSTANCE_SET,
INSTANCE_DELETE,
INSTANCE_MOUNT,
INSTANCE_DESTROY
INSTANCE_DESTROY,
OPTIONS_DATA_FN,
OPTIONS_DATA_MERGE
}
type DeprecationData = {
message: string | (() => string)
message: string | ((...args: any[]) => string)
link?: string
}
@ -120,17 +124,31 @@ const deprecations: Record<DeprecationTypes, DeprecationData> = {
[DeprecationTypes.INSTANCE_DESTROY]: {
message: `vm.$destroy() has been removed. Use app.unmount() instead.`,
link: `https://v3.vuejs.org/api/application-api.html#unmount`
},
[DeprecationTypes.OPTIONS_DATA_FN]: {
message:
`The "data" option can no longer be a plain object. ` +
`Always use a function.`,
link: `https://v3.vuejs.org/guide/migration/data-option.html`
},
[DeprecationTypes.OPTIONS_DATA_MERGE]: {
message: (key: string) =>
`Detected conflicting key "${key}" when merging "data" option values. ` +
`In Vue 3, data keys are merged shallowly and will override one another.`,
link: `https://v3.vuejs.org/guide/migration/data-option.html#mixin-merge-behavior-change`
}
}
export function warnDeprecation(key: DeprecationTypes) {
export function warnDeprecation(key: DeprecationTypes, ...args: any[]) {
if (!__COMPAT__ || !__DEV__) {
return
}
const { message, link } = deprecations[key]
console.warn(
`[Vue Deprecation]: ${typeof message === 'function' ? message() : message}${
link ? `\nFor more details, see ${link}` : ``
}`
warn(
`[DEPRECATION] ${
typeof message === 'function' ? message(...args) : message
}${link ? `\nFor more details, see ${link}` : ``}`
)
}

View File

@ -162,9 +162,14 @@ export function createCompatVue(
if (!inlineOptions) {
return createCompatApp(options, SubVue)
} else {
const { el, data } = inlineOptions
if (data && !isFunction(data)) {
__DEV__ && warnDeprecation(DeprecationTypes.OPTIONS_DATA_FN)
inlineOptions.data = () => data
}
return createCompatApp(
{
el: inlineOptions.el,
el,
extends: options,
mixins: [inlineOptions]
},

View File

@ -65,6 +65,7 @@ import { warn } from './warning'
import { VNodeChild } from './vnode'
import { callWithAsyncErrorHandling } from './errorHandling'
import { UnionToIntersection } from './helpers/typeUtils'
import { deepMergeData } from './compat/data'
/**
* Interface for declaring custom options.
@ -904,7 +905,11 @@ function resolveData(
instance.data = reactive(data)
} else {
// existing data: this is a mixin or extends.
extend(instance.data, data)
if (__COMPAT__) {
deepMergeData(instance.data, data)
} else {
extend(instance.data, data)
}
}
}

View File

@ -71,7 +71,7 @@ export function warn(msg: string, ...args: any[]) {
resetTracking()
}
function getComponentTrace(): ComponentTraceStack {
export function getComponentTrace(): ComponentTraceStack {
let currentVNode: VNode | null = stack[stack.length - 1]
if (!currentVNode) {
return []