createApp,
shallowReadonly
} from '@vue/runtime-test'
-import { ComponentInternalInstance } from '../src/component'
+import { ComponentInternalInstance, ComponentOptions } from '../src/component'
describe('component: proxy', () => {
test('data', () => {
expect(instanceProxy.$root).toBe(instance!.root.proxy)
expect(instanceProxy.$emit).toBe(instance!.emit)
expect(instanceProxy.$el).toBe(instance!.vnode.el)
- expect(instanceProxy.$options).toBe(instance!.type)
+ expect(instanceProxy.$options).toBe(
+ (instance!.type as ComponentOptions).__merged
+ )
expect(() => (instanceProxy.$data = {})).toThrow(TypeError)
expect(`Attempting to mutate public property "$data"`).toHaveBeenWarned()
return comp
}
+ // 2.x constructor
+ if (isFunction(comp) && comp.cid) {
+ comp = comp.options
+ }
+
// 2.x async component
- // since after disabling this, plain functions are still valid usage, do not
- // use softAssert here.
if (
isFunction(comp) &&
checkCompatEnabled(DeprecationTypes.COMPONENT_ASYNC, instance, comp)
) {
+ // since after disabling this, plain functions are still valid usage, do not
+ // use softAssert here.
return convertLegacyAsyncComponent(comp)
}
* @deprecated filters have been removed from Vue 3.
*/
filter(name: string, arg: any): null
+ /**
+ * @internal
+ */
+ cid: number
+ /**
+ * @internal
+ */
+ options: ComponentOptions
configureCompat: typeof configureCompat
}
} as any
const singletonApp = createApp({})
- // @ts-ignore
- singletonApp.prototype = singletonApp.config.globalProperties
function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null)
Vue.version = __VERSION__
Vue.config = singletonApp.config
Vue.nextTick = nextTick
+ Vue.options = { _base: Vue }
+
+ let cid = 1
+ Vue.cid = cid
- Vue.extend = ((options: ComponentOptions = {}) => {
+ function extendCtor(this: any, extendOptions: ComponentOptions = {}) {
assertCompatEnabled(DeprecationTypes.GLOBAL_EXTEND, null)
+ if (isFunction(extendOptions)) {
+ extendOptions = extendOptions.options
+ }
+ const Super = this
function SubVue(inlineOptions?: ComponentOptions) {
if (!inlineOptions) {
- return createCompatApp(options, SubVue)
+ return createCompatApp(extendOptions, SubVue)
} else {
return createCompatApp(
{
el: inlineOptions.el,
- extends: options,
+ extends: extendOptions,
mixins: [inlineOptions]
},
SubVue
}
SubVue.prototype = Object.create(Vue.prototype)
SubVue.prototype.constructor = SubVue
+ SubVue.options = mergeOptions(
+ extend({}, Super.options) as ComponentOptions,
+ extendOptions
+ )
+
+ SubVue.options._base = SubVue
+ SubVue.extend = extendCtor.bind(SubVue)
+ SubVue.mixin = Super.mixin
+ SubVue.use = Super.use
+ SubVue.cid = ++cid
return SubVue
- }) as any
+ }
+
+ Vue.extend = extendCtor.bind(Vue) as any
Vue.set = (target, key, value) => {
assertCompatEnabled(DeprecationTypes.GLOBAL_SET, null)
}
Vue.use = (p, ...options) => {
- singletonApp.use(p, ...options)
+ if (p && isFunction(p.install)) {
+ p.install(Vue as any, ...options)
+ } else if (isFunction(p)) {
+ p(Vue as any, ...options)
+ }
return Vue
}
strats.watch = mergeObjectOptions
}
-function mergeHook(to: Function[] | undefined, from: Function | Function[]) {
- return Array.from(new Set([...(to || []), from]))
+function mergeHook(
+ to: Function[] | Function | undefined,
+ from: Function | Function[]
+) {
+ return Array.from(new Set([...(isArray(to) ? to : to ? [to] : []), from]))
}
function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
legacyresolveScopedSlots
} from './renderHelpers'
import { resolveFilter } from '../helpers/resolveAssets'
+import { resolveMergedOptions } from '../componentOptions'
export function installCompatInstanceProperties(map: PublicPropertiesMap) {
const set = (target: any, key: any, val: any) => {
$children: getCompatChildren,
$listeners: getCompatListeners,
+ // inject parent into $options for compat
+ $options: i => {
+ let res = resolveMergedOptions(i)
+ if (res === i.type) res = i.type.__merged = extend({}, res)
+ res.parent = i.proxy!.$parent
+ return res
+ },
+
// v2 render helpers
$createElement: () => compatH,
_self: i => i.proxy,
+ _uid: i => i.uid,
_c: () => compatH,
_o: () => legacyMarkOnce,
_n: () => toNumber,
hyphenate,
isArray,
isObject,
+ isString,
makeMap,
normalizeClass,
normalizeStyle,
if (
isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, currentRenderingInstance)
) {
+ const context = currentRenderingInstance
const getInstance = () => vnode.component && vnode.component.proxy
let componentOptions: any
Object.defineProperties(vnode, {
+ tag: { get: () => vnode.type },
+ data: { get: () => vnode.props, set: p => (vnode.props = p) },
elm: { get: () => vnode.el },
componentInstance: { get: getInstance },
child: { get: getInstance },
+ text: { get: () => (isString(vnode.children) ? vnode.children : null) },
+ context: { get: () => context && context.proxy },
componentOptions: {
get: () => {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
deferredProvide: (Data | Function)[] = [],
asMixin: boolean = false
) {
+ if (__COMPAT__ && isFunction(options)) {
+ options = options.options
+ }
+
const {
// composition
mixins,
from: any,
instance?: ComponentInternalInstance
) {
+ if (__COMPAT__ && isFunction(from)) {
+ from = from.options
+ }
+
const strats = instance && instance.appContext.config.optionMergeStrategies
const { mixins, extends: extendsOptions } = from
to[key] = from[key]
}
}
+ return to
}
let hasExtends = false
if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) {
const extendProps = (raw: ComponentOptions) => {
+ if (__COMPAT__ && isFunction(raw)) {
+ raw = raw.options
+ }
hasExtends = true
const [props, keys] = normalizePropsOptions(raw, appContext, true)
extend(normalized, props)
instance: ComponentInternalInstance,
children: VNodeNormalizedChildren
) => {
- if (__DEV__ && !isKeepAlive(instance.vnode)) {
+ if (
+ __DEV__ &&
+ !isKeepAlive(instance.vnode) &&
+ !(__COMPAT__ && isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, instance))
+ ) {
warn(
`Non-function value encountered for default slot. ` +
`Prefer function slots for better performance.`