import { isReactive , reactive , track , TrackOpTypes , trigger , TriggerOpTypes } from '@vue/reactivity' ; import { isFunction , extend , NOOP , isArray , isObject , isString , invokeArrayFns } from '@vue/shared' ; import { warn } from '../warning' ; import { cloneVNode , createVNode } from '../vnode' ; import { RootRenderFunction } from '../renderer' ; import { App , AppConfig , AppContext , CreateAppFunction , Plugin } from '../apiCreateApp' ; import { Component , ComponentOptions , createComponentInstance , finishComponentSetup , isRuntimeOnly , setupComponent } from '../component' ; import { RenderFunction , mergeOptions , internalOptionMergeStrats } from '../componentOptions' ; import { ComponentPublicInstance } from '../componentPublicInstance' ; import { devtoolsInitApp , devtoolsUnmountApp } from '../devtools' ; import { Directive } from '../directives' ; import { nextTick } from '../scheduler' ; import { version } from '..' ; import { installLegacyConfigWarnings , installLegacyOptionMergeStrats , LegacyConfig } from './globalConfig' ; import { LegacyDirective } from './customDirective' ; import { warnDeprecation , DeprecationTypes , assertCompatEnabled , configureCompat , isCompatEnabled , softAssertCompatEnabled } from './compatConfig' ; import { LegacyPublicInstance } from './instance' ; deprecated export type CompatVue = Pick < App , 'version' | 'component' | 'directive' > & { configureCompat : typeof configureCompat ; new ( options ? ) : LegacyPublicInstance ; version : string ; config : AppConfig & LegacyConfig ; nextTick : typeof nextTick ; use ( plugin , ... options ) : CompatVue ; mixin ( mixin ) : CompatVue ; component ( name ) : Component | undefined ; component ( name , component ) : CompatVue ; directive ( name ) : Directive | undefined ; directive ( name , directive ) : CompatVue ; compile ( template ) : RenderFunction ; deprecated extend : ( options ? : ComponentOptions ) => CompatVue ; deprecated set ( target , key , value ) : void ; deprecated delete ( target , key ) : void ; deprecated observable : typeof reactive ; deprecated filter ( name , arg ? ) : null ; internal cid : number ; internal options : ComponentOptions ; internal util : any ; internal super : CompatVue ; } ; export let isCopyingConfig = false ; export let singletonApp ; let singletonCtor ; export function createCompatVue ( createApp , createSingletonApp ) { singletonApp = createSingletonApp ( { } ) ; const Vue = ( singletonCtor = function Vue ( options = { } ) { return createCompatApp ( options , Vue ) ; } as any ) ; function createCompatApp ( options = { } , Ctor ) { assertCompatEnabled ( DeprecationTypes . GLOBAL_MOUNT , null ) ; const { data } = options ; if ( data && ! isFunction ( data ) && softAssertCompatEnabled ( DeprecationTypes . OPTIONS_DATA_FN , null ) ) { options . data = ( ) => data ; } const app = createApp ( options ) ; if ( Ctor !== Vue ) { applySingletonPrototype ( app , Ctor ) ; } const vm = app . _createRoot ! ( options ) ; if ( options . el ) { return ( vm as any ) . $mount ( options . el ) ; } else { return vm ; } } Vue . version = __VERSION__ ; Vue . config = singletonApp . config ; Vue . 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 ; } ; Vue . mixin = m => { singletonApp . mixin ( m ) ; return Vue ; } ; Vue . component = ( ( name , comp ) => { if ( comp ) { singletonApp . component ( name , comp ) ; return Vue ; } else { return singletonApp . component ( name ) ; } } ) as any ; Vue . directive = ( ( name , dir ) => { if ( dir ) { singletonApp . directive ( name , dir as Directive ) ; return Vue ; } else { return singletonApp . directive ( name ) ; } } ) as any ; Vue . options = { _base : Vue } ; let cid = 1 ; Vue . cid = cid ; Vue . nextTick = nextTick ; const extendCache = new WeakMap ( ) ; function extendCtor ( this , extendOptions = { } ) { assertCompatEnabled ( DeprecationTypes . GLOBAL_EXTEND , null ) ; if ( isFunction ( extendOptions ) ) { extendOptions = extendOptions . options ; } if ( extendCache . has ( extendOptions ) ) { return extendCache . get ( extendOptions ) ; } const Super = this ; function SubVue ( inlineOptions ? ) { if ( ! inlineOptions ) { return createCompatApp ( SubVue . options , SubVue ) ; } else { return createCompatApp ( mergeOptions ( extend ( { } , SubVue . options ) , inlineOptions , internalOptionMergeStrats as any ) , SubVue ) ; } } SubVue . super = Super ; SubVue . prototype = Object . create ( Vue . prototype ) ; SubVue . prototype . constructor = SubVue ; const mergeBase = { } ; for ( const key in Super . options ) { const superValue = Super . options [ key ] ; mergeBase [ key ] = isArray ( superValue ) ? superValue . slice ( ) : isObject ( superValue ) ? extend ( Object . create ( null ) , superValue ) : superValue ; } SubVue . options = mergeOptions ( mergeBase , extendOptions , internalOptionMergeStrats as any ) ; SubVue . options . _base = SubVue ; SubVue . extend = extendCtor . bind ( SubVue ) ; SubVue . mixin = Super . mixin ; SubVue . use = Super . use ; SubVue . cid = ++ cid ; extendCache . set ( extendOptions , SubVue ) ; return SubVue ; } Vue . extend = extendCtor . bind ( Vue ) as any ; Vue . set = ( target , key , value ) => { assertCompatEnabled ( DeprecationTypes . GLOBAL_SET , null ) ; target [ key ] = value ; } ; Vue . delete = ( target , key ) => { assertCompatEnabled ( DeprecationTypes . GLOBAL_DELETE , null ) ; delete target [ key ] ; } ; Vue . observable = ( target ) => { assertCompatEnabled ( DeprecationTypes . GLOBAL_OBSERVABLE , null ) ; return reactive ( target ) ; } ; Vue . filter = ( ( name , filter ? ) => { if ( filter ) { singletonApp . filter ! ( name , filter ) ; return Vue ; } else { return singletonApp . filter ! ( name ) ; } } ) as any ; const util = { warn : __DEV__ ? warn : NOOP , extend , mergeOptions : ( parent , child , vm ? ) => mergeOptions ( parent , child , vm ? undefined : ( internalOptionMergeStrats as any ) ) , defineReactive } ; Object . defineProperty ( Vue , 'util' , { get ( ) { assertCompatEnabled ( DeprecationTypes . GLOBAL_PRIVATE_UTIL , null ) ; return util ; } } ) ; Vue . configureCompat = configureCompat ; return Vue ; } export function installAppCompatProperties ( app , context , render ) { installFilterMethod ( app , context ) ; installLegacyOptionMergeStrats ( app . config ) ; if ( ! singletonApp ) { return ; } installCompatMount ( app , context , render ) ; installLegacyAPIs ( app ) ; applySingletonAppMutations ( app ) ; if ( __DEV__ ) installLegacyConfigWarnings ( app . config ) ; } function installFilterMethod ( app , context ) { context . filters = { } ; app . filter = ( name , filter ? ) : any => { assertCompatEnabled ( DeprecationTypes . FILTERS , null ) ; if ( ! filter ) { return context . filters ! [ name ] ; } if ( __DEV__ && context . filters ! [ name ] ) { warn ( `Filter "${ name }" has already been registered.` ) ; } context . filters ! [ name ] = filter ; return app ; } ; } function installLegacyAPIs ( app ) { Object . defineProperties ( app , { prototype : { get ( ) { __DEV__ && warnDeprecation ( DeprecationTypes . GLOBAL_PROTOTYPE , null ) ; return app . config . globalProperties ; } } , nextTick : { value : nextTick } , extend : { value : singletonCtor . extend } , set : { value : singletonCtor . set } , delete : { value : singletonCtor . delete } , observable : { value : singletonCtor . observable } , util : { get ( ) { return singletonCtor . util ; } } } ) ; } function applySingletonAppMutations ( app ) { ; [ 'mixins' , 'components' , 'directives' , 'filters' , 'deopt' ] . forEach ( key => { app . _context [ key ] = singletonApp . _context [ key ] ; } ) ; isCopyingConfig = true ; for ( const key in singletonApp . config ) { if ( key === 'isNativeTag' ) continue ; if ( isRuntimeOnly ( ) && ( key === 'isCustomElement' || key === 'compilerOptions' ) ) { continue ; } const val = singletonApp . config [ key as keyof AppConfig ] ; app . config [ key ] = val ; if ( key === 'ignoredElements' && isCompatEnabled ( DeprecationTypes . CONFIG_IGNORED_ELEMENTS , null ) && ! isRuntimeOnly ( ) && isArray ( val ) ) { app . config . compilerOptions . isCustomElement = tag => { return val . some ( v => ( isString ( v ) ? v === tag : v . test ( tag ) ) ) ; } ; } } isCopyingConfig = false ; applySingletonPrototype ( app , singletonCtor ) ; } function applySingletonPrototype ( app , Ctor ) { const enabled = isCompatEnabled ( DeprecationTypes . GLOBAL_PROTOTYPE , null ) ; if ( enabled ) { app . config . globalProperties = Object . create ( Ctor . prototype ) ; } let hasPrototypeAugmentations = false ; const descriptors = Object . getOwnPropertyDescriptors ( Ctor . prototype ) ; for ( const key in descriptors ) { if ( key !== 'constructor' ) { hasPrototypeAugmentations = true ; if ( enabled ) { Object . defineProperty ( app . config . globalProperties , key , descriptors [ key ] ) ; } } } if ( __DEV__ && hasPrototypeAugmentations ) { warnDeprecation ( DeprecationTypes . GLOBAL_PROTOTYPE , null ) ; } } function installCompatMount ( app , context , render ) { let isMounted = false ; /**
     * Vue 2 supports the behavior of creating a component instance but not
     * mounting it, which is no longer possible in Vue 3 - this internal
     * function simulates that behavior.
     */ app . _createRoot = options => { const component = app . _component ; const vnode = createVNode ( component , options . propsData || null ) ; vnode . appContext = context ; const hasNoRender = ! isFunction ( component ) && ! component . render && ! component . template ; const emptyRender = ( ) => { } ; const instance = createComponentInstance ( vnode , null , null ) ; if ( hasNoRender ) { instance . render = emptyRender ; } setupComponent ( instance ) ; vnode . component = instance ; vnode . isCompatRoot = true ; instance . ctx . _compat_mount = ( selectorOrEl ? ) => { if ( isMounted ) { __DEV__ && warn ( `Root instance is already mounted.` ) ; return ; } let container ; if ( typeof selectorOrEl === 'string' ) { const result = document . querySelector ( selectorOrEl ) ; if ( ! result ) { __DEV__ && warn ( `Failed to mount root instance: selector "${ selectorOrEl }" returned null.` ) ; return ; } container = result ; } else { container = selectorOrEl || document . createElement ( 'div' ) ; } const isSVG = container instanceof SVGElement ; if ( __DEV__ ) { context . reload = ( ) => { const cloned = cloneVNode ( vnode ) ; cloned . component = null ; render ( cloned , container , isSVG ) ; } ; } if ( hasNoRender && instance . render === emptyRender ) { if ( __DEV__ ) { for ( let i = 0 ; i < container . attributes . length ; i ++ ) { const attr = container . attributes [ i ] ; if ( attr . name !== 'v-cloak' && /^(v-|:|@)/ . test ( attr . name ) ) { warnDeprecation ( DeprecationTypes . GLOBAL_MOUNT_CONTAINER , null ) ; break ; } } } instance . render = null ; ( component as ComponentOptions ) . template = container . innerHTML ; finishComponentSetup ( instance , false , true ) ; } container . innerHTML = '' ; render ( vnode , container , isSVG ) ; if ( container instanceof Element ) { container . removeAttribute ( 'v-cloak' ) ; container . setAttribute ( 'data-v-app' , '' ) ; } isMounted = true ; app . _container = container ; ( container as any ) . __vue_app__ = app ; if ( __DEV__ || __FEATURE_PROD_DEVTOOLS__ ) { devtoolsInitApp ( app , version ) ; } return instance . proxy ! ; } ; instance . ctx . _compat_destroy = ( ) => { if ( isMounted ) { render ( null , app . _container ) ; if ( __DEV__ || __FEATURE_PROD_DEVTOOLS__ ) { devtoolsUnmountApp ( app ) ; } delete app . _container . __vue_app__ ; } else { const { bum , scope , um } = instance ; if ( bum ) { invokeArrayFns ( bum ) ; } if ( isCompatEnabled ( DeprecationTypes . INSTANCE_EVENT_HOOKS , instance ) ) { instance . emit ( 'hook:beforeDestroy' ) ; } if ( scope ) { scope . stop ( ) ; } if ( um ) { invokeArrayFns ( um ) ; } if ( isCompatEnabled ( DeprecationTypes . INSTANCE_EVENT_HOOKS , instance ) ) { instance . emit ( 'hook:destroyed' ) ; } } } ; return instance . proxy ! ; } ; } const methodsToPatch = [ 'push' , 'pop' , 'shift' , 'unshift' , 'splice' , 'sort' , 'reverse' ] ; const patched = new WeakSet < object > ( ) ; function defineReactive ( obj , key , val ) { if ( isObject ( val ) && ! isReactive ( val ) && ! patched . has ( val ) ) { const reactiveVal = reactive ( val ) ; if ( isArray ( val ) ) { methodsToPatch . forEach ( m => { val [ m ] = ( ... args ) => { Array . prototype [ m ] . call ( reactiveVal , ... args ) ; } ; } ) ; } else { Object . keys ( val ) . forEach ( key => { try { defineReactiveSimple ( val , key , val [ key ] ) ; } catch ( e ) { } } ) ; } } const i = obj . $ ; if ( i && obj === i . proxy ) { defineReactiveSimple ( i . ctx , key , val ) ; i . accessCache = Object . create ( null ) ; } else if ( isReactive ( obj ) ) { obj [ key ] = val ; } else { defineReactiveSimple ( obj , key , val ) ; } } function defineReactiveSimple ( obj , key , val ) { val = isObject ( val ) ? reactive ( val ) : val ; Object . defineProperty ( obj , key , { enumerable : true , configurable : true , get ( ) { track ( obj , TrackOpTypes . GET , key ) ; return val ; } , set ( newVal ) { val = isObject ( newVal ) ? reactive ( newVal ) : newVal ; trigger ( obj , TriggerOpTypes . SET , key , newVal ) ; } } ) ; }