2020-02-16 10:04:29 +08:00
|
|
|
import {
|
2023-05-19 07:49:28 +08:00
|
|
|
type Component,
|
2021-09-22 00:55:08 +08:00
|
|
|
type ComponentInternalInstance,
|
2020-08-20 04:11:29 +08:00
|
|
|
type ConcreteComponent,
|
2020-02-16 10:04:29 +08:00
|
|
|
type Data,
|
2024-06-10 17:37:32 +08:00
|
|
|
getComponentPublicInstance,
|
2020-02-16 10:04:29 +08:00
|
|
|
validateComponentName,
|
|
|
|
} from './component'
|
2021-06-03 02:37:27 +08:00
|
|
|
import type {
|
|
|
|
ComponentOptions,
|
|
|
|
MergedComponentOptions,
|
|
|
|
RuntimeCompilerOptions,
|
|
|
|
} from './componentOptions'
|
2022-10-26 17:00:47 +08:00
|
|
|
import type {
|
|
|
|
ComponentCustomProperties,
|
|
|
|
ComponentPublicInstance,
|
|
|
|
} from './componentPublicInstance'
|
2019-10-19 00:34:45 +08:00
|
|
|
import { type Directive, validateDirectiveName } from './directives'
|
2023-12-08 18:25:01 +08:00
|
|
|
import type { ElementNamespace, RootRenderFunction } from './renderer'
|
2019-09-03 04:09:34 +08:00
|
|
|
import type { InjectionKey } from './apiInject'
|
|
|
|
import { warn } from './warning'
|
2020-02-14 12:31:03 +08:00
|
|
|
import { type VNode, cloneVNode, createVNode } from './vnode'
|
2020-03-23 23:08:22 +08:00
|
|
|
import type { RootHydrateFunction } from './hydration'
|
2020-07-21 09:51:30 +08:00
|
|
|
import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
|
2023-02-03 09:54:15 +08:00
|
|
|
import { NO, extend, isFunction, isObject } from '@vue/shared'
|
2020-06-26 21:03:55 +08:00
|
|
|
import { version } from '.'
|
2021-05-07 05:15:11 +08:00
|
|
|
import { installAppCompatProperties } from './compat/global'
|
2021-06-03 03:22:52 +08:00
|
|
|
import type { NormalizedPropsOptions } from './componentProps'
|
|
|
|
import type { ObjectEmitsOptions } from './componentEmits'
|
2024-04-29 18:47:56 +08:00
|
|
|
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
2023-11-22 22:18:02 +08:00
|
|
|
import type { DefineComponent } from './apiDefineComponent'
|
2019-09-03 04:09:34 +08:00
|
|
|
|
2019-09-07 04:58:32 +08:00
|
|
|
export interface App<HostElement = any> {
|
2020-06-26 21:03:55 +08:00
|
|
|
version: string
|
2019-09-03 04:09:34 +08:00
|
|
|
config: AppConfig
|
2022-11-14 09:13:32 +08:00
|
|
|
|
|
|
|
use<Options extends unknown[]>(
|
|
|
|
plugin: Plugin<Options>,
|
2025-03-19 11:44:32 +08:00
|
|
|
...options: NoInfer<Options>
|
2022-11-14 09:13:32 +08:00
|
|
|
): this
|
2025-03-19 11:44:32 +08:00
|
|
|
use<Options>(plugin: Plugin<Options>, options: NoInfer<Options>): this
|
2022-11-14 09:13:32 +08:00
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
mixin(mixin: ComponentOptions): this
|
2020-08-20 04:11:29 +08:00
|
|
|
component(name: string): Component | undefined
|
2024-05-04 07:29:23 +08:00
|
|
|
component<T extends Component | DefineComponent>(
|
|
|
|
name: string,
|
|
|
|
component: T,
|
|
|
|
): this
|
2024-09-16 10:30:04 +08:00
|
|
|
directive<
|
|
|
|
HostElement = any,
|
|
|
|
Value = any,
|
|
|
|
Modifiers extends string = string,
|
|
|
|
Arg extends string = string,
|
|
|
|
>(
|
|
|
|
name: string,
|
|
|
|
): Directive<HostElement, Value, Modifiers, Arg> | undefined
|
|
|
|
directive<
|
|
|
|
HostElement = any,
|
|
|
|
Value = any,
|
|
|
|
Modifiers extends string = string,
|
|
|
|
Arg extends string = string,
|
|
|
|
>(
|
|
|
|
name: string,
|
|
|
|
directive: Directive<HostElement, Value, Modifiers, Arg>,
|
|
|
|
): this
|
2020-02-14 12:31:03 +08:00
|
|
|
mount(
|
|
|
|
rootContainer: HostElement | string,
|
2024-08-07 16:07:47 +08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
2021-03-02 00:51:32 +08:00
|
|
|
isHydrate?: boolean,
|
2024-08-07 16:07:47 +08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
2023-12-08 18:25:01 +08:00
|
|
|
namespace?: boolean | ElementNamespace,
|
2024-08-07 16:07:47 +08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
vnode?: VNode,
|
2020-02-14 12:31:03 +08:00
|
|
|
): ComponentPublicInstance
|
2021-02-04 02:09:59 +08:00
|
|
|
unmount(): void
|
2024-04-29 18:47:56 +08:00
|
|
|
onUnmount(cb: () => void): void
|
2024-06-10 16:09:46 +08:00
|
|
|
provide<T, K = InjectionKey<T> | string | number>(
|
|
|
|
key: K,
|
|
|
|
value: K extends InjectionKey<infer V> ? V : T,
|
|
|
|
): this
|
2020-01-24 10:01:56 +08:00
|
|
|
|
2023-04-05 15:18:13 +08:00
|
|
|
/**
|
|
|
|
* Runs a function with the app as active instance. This allows using of `inject()` within the function to get access
|
|
|
|
* to variables provided via `app.provide()`.
|
|
|
|
*
|
|
|
|
* @param fn - function to run with the app as active instance
|
|
|
|
*/
|
|
|
|
runWithContext<T>(fn: () => T): T
|
|
|
|
|
2020-07-21 09:51:30 +08:00
|
|
|
// internal, but we need to expose these for the server-renderer and devtools
|
2020-09-01 06:32:07 +08:00
|
|
|
_uid: number
|
2020-08-20 04:11:29 +08:00
|
|
|
_component: ConcreteComponent
|
2020-01-24 10:01:56 +08:00
|
|
|
_props: Data | null
|
|
|
|
_container: HostElement | null
|
2020-01-31 01:20:23 +08:00
|
|
|
_context: AppContext
|
2021-06-08 05:23:45 +08:00
|
|
|
_instance: ComponentInternalInstance | null
|
2021-04-05 23:54:35 +08:00
|
|
|
|
2024-08-07 16:07:47 +08:00
|
|
|
/**
|
|
|
|
* @internal custom element vnode
|
|
|
|
*/
|
|
|
|
_ceVNode?: VNode
|
|
|
|
|
2021-04-05 23:54:35 +08:00
|
|
|
/**
|
2021-04-20 00:08:26 +08:00
|
|
|
* v2 compat only
|
|
|
|
*/
|
|
|
|
filter?(name: string): Function | undefined
|
|
|
|
filter?(name: string, filter: Function): this
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal v3 compat only
|
2021-04-05 23:54:35 +08:00
|
|
|
*/
|
|
|
|
_createRoot?(options: ComponentOptions): ComponentPublicInstance
|
2019-09-03 04:09:34 +08:00
|
|
|
}
|
|
|
|
|
2021-06-02 22:37:50 +08:00
|
|
|
export type OptionMergeFunction = (to: unknown, from: unknown) => any
|
2020-03-24 23:59:00 +08:00
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
export interface AppConfig {
|
2020-03-24 23:59:00 +08:00
|
|
|
// @private
|
2024-02-25 20:41:08 +08:00
|
|
|
readonly isNativeTag: (tag: string) => boolean
|
2020-03-24 23:59:00 +08:00
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
performance: boolean
|
2020-03-24 23:59:00 +08:00
|
|
|
optionMergeStrategies: Record<string, OptionMergeFunction>
|
2022-10-26 17:00:47 +08:00
|
|
|
globalProperties: ComponentCustomProperties & Record<string, any>
|
2019-09-03 04:09:34 +08:00
|
|
|
errorHandler?: (
|
2020-03-10 03:58:52 +08:00
|
|
|
err: unknown,
|
2019-09-07 00:58:31 +08:00
|
|
|
instance: ComponentPublicInstance | null,
|
2019-09-03 04:09:34 +08:00
|
|
|
info: string,
|
|
|
|
) => void
|
|
|
|
warnHandler?: (
|
|
|
|
msg: string,
|
2019-09-07 00:58:31 +08:00
|
|
|
instance: ComponentPublicInstance | null,
|
2019-09-03 04:09:34 +08:00
|
|
|
trace: string,
|
|
|
|
) => void
|
2021-04-26 23:46:29 +08:00
|
|
|
|
2021-07-28 05:52:31 +08:00
|
|
|
/**
|
2021-12-12 00:14:25 +08:00
|
|
|
* Options to pass to `@vue/compiler-dom`.
|
2021-07-28 05:52:31 +08:00
|
|
|
* Only supported in runtime compiler build.
|
|
|
|
*/
|
|
|
|
compilerOptions: RuntimeCompilerOptions
|
|
|
|
|
2021-04-26 23:46:29 +08:00
|
|
|
/**
|
|
|
|
* @deprecated use config.compilerOptions.isCustomElement
|
|
|
|
*/
|
|
|
|
isCustomElement?: (tag: string) => boolean
|
2024-02-25 20:38:33 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* TODO document for 3.5
|
|
|
|
* Enable warnings for computed getters that recursively trigger itself.
|
|
|
|
*/
|
|
|
|
warnRecursiveComputed?: boolean
|
2024-07-17 10:05:09 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether to throw unhandled errors in production.
|
|
|
|
* Default is `false` to avoid crashing on any error (and only logs it)
|
|
|
|
* But in some cases, e.g. SSR, throwing might be more desirable.
|
|
|
|
*/
|
|
|
|
throwUnhandledErrorInProduction?: boolean
|
2024-07-19 18:06:02 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Prefix for all useId() calls within this app
|
|
|
|
*/
|
|
|
|
idPrefix?: string
|
2019-09-03 04:09:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface AppContext {
|
2020-07-21 09:51:30 +08:00
|
|
|
app: App // for devtools
|
2019-09-03 04:09:34 +08:00
|
|
|
config: AppConfig
|
|
|
|
mixins: ComponentOptions[]
|
2020-08-20 04:11:29 +08:00
|
|
|
components: Record<string, Component>
|
2019-09-03 04:09:34 +08:00
|
|
|
directives: Record<string, Directive>
|
|
|
|
provides: Record<string | symbol, any>
|
2021-06-02 22:37:50 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Cache for merged/normalized component options
|
|
|
|
* Each app instance has its own cache because app-level global mixins and
|
|
|
|
* optionMergeStrategies can affect merge behavior.
|
2021-06-03 03:22:52 +08:00
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
optionsCache: WeakMap<ComponentOptions, MergedComponentOptions>
|
|
|
|
/**
|
|
|
|
* Cache for normalized props options
|
|
|
|
* @internal
|
2021-06-02 22:37:50 +08:00
|
|
|
*/
|
2021-06-03 03:22:52 +08:00
|
|
|
propsCache: WeakMap<ConcreteComponent, NormalizedPropsOptions>
|
2020-10-07 03:31:29 +08:00
|
|
|
/**
|
2021-06-03 03:22:52 +08:00
|
|
|
* Cache for normalized emits options
|
2020-10-07 03:31:29 +08:00
|
|
|
* @internal
|
|
|
|
*/
|
2021-06-03 03:22:52 +08:00
|
|
|
emitsCache: WeakMap<ConcreteComponent, ObjectEmitsOptions | null>
|
2020-10-07 03:31:29 +08:00
|
|
|
/**
|
|
|
|
* HMR only
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
reload?: () => void
|
2021-04-20 00:08:26 +08:00
|
|
|
/**
|
|
|
|
* v2 compat only
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
filters?: Record<string, Function>
|
2019-09-03 04:09:34 +08:00
|
|
|
}
|
|
|
|
|
2023-12-11 22:04:56 +08:00
|
|
|
type PluginInstallFunction<Options = any[]> = Options extends unknown[]
|
2022-11-14 09:13:32 +08:00
|
|
|
? (app: App, ...options: Options) => any
|
|
|
|
: (app: App, options: Options) => any
|
2019-09-03 04:09:34 +08:00
|
|
|
|
2023-12-11 22:04:56 +08:00
|
|
|
export type ObjectPlugin<Options = any[]> = {
|
|
|
|
install: PluginInstallFunction<Options>
|
|
|
|
}
|
|
|
|
export type FunctionPlugin<Options = any[]> = PluginInstallFunction<Options> &
|
|
|
|
Partial<ObjectPlugin<Options>>
|
|
|
|
|
2025-03-19 11:44:32 +08:00
|
|
|
export type Plugin<
|
|
|
|
Options = any[],
|
|
|
|
// TODO: in next major Options extends unknown[] and remove P
|
|
|
|
P extends unknown[] = Options extends unknown[] ? Options : [Options],
|
|
|
|
> = FunctionPlugin<P> | ObjectPlugin<P>
|
2019-09-03 04:09:34 +08:00
|
|
|
|
|
|
|
export function createAppContext(): AppContext {
|
|
|
|
return {
|
2020-07-21 09:51:30 +08:00
|
|
|
app: null as any,
|
2019-09-03 04:09:34 +08:00
|
|
|
config: {
|
2020-03-24 23:59:00 +08:00
|
|
|
isNativeTag: NO,
|
2019-09-03 04:09:34 +08:00
|
|
|
performance: false,
|
2020-03-25 21:28:37 +08:00
|
|
|
globalProperties: {},
|
2020-03-24 23:59:00 +08:00
|
|
|
optionMergeStrategies: {},
|
2019-09-03 04:09:34 +08:00
|
|
|
errorHandler: undefined,
|
2021-04-26 23:46:29 +08:00
|
|
|
warnHandler: undefined,
|
2021-04-29 00:36:08 +08:00
|
|
|
compilerOptions: {},
|
2019-09-03 04:09:34 +08:00
|
|
|
},
|
|
|
|
mixins: [],
|
|
|
|
components: {},
|
|
|
|
directives: {},
|
2021-06-02 22:37:50 +08:00
|
|
|
provides: Object.create(null),
|
2021-06-03 03:22:52 +08:00
|
|
|
optionsCache: new WeakMap(),
|
|
|
|
propsCache: new WeakMap(),
|
|
|
|
emitsCache: new WeakMap(),
|
2019-09-03 04:09:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:05:38 +08:00
|
|
|
export type CreateAppFunction<HostElement> = (
|
2020-08-20 04:11:29 +08:00
|
|
|
rootComponent: Component,
|
2020-01-24 04:05:38 +08:00
|
|
|
rootProps?: Data | null,
|
|
|
|
) => App<HostElement>
|
|
|
|
|
2020-09-01 06:32:07 +08:00
|
|
|
let uid = 0
|
|
|
|
|
2023-07-12 11:38:59 +08:00
|
|
|
export function createAppAPI<HostElement>(
|
2022-08-31 14:02:48 +08:00
|
|
|
render: RootRenderFunction<HostElement>,
|
2020-03-23 23:08:22 +08:00
|
|
|
hydrate?: RootHydrateFunction,
|
2020-01-24 04:05:38 +08:00
|
|
|
): CreateAppFunction<HostElement> {
|
2020-03-23 23:08:22 +08:00
|
|
|
return function createApp(rootComponent, rootProps = null) {
|
2022-04-12 15:14:23 +08:00
|
|
|
if (!isFunction(rootComponent)) {
|
2023-02-03 09:54:15 +08:00
|
|
|
rootComponent = extend({}, rootComponent)
|
2022-04-12 15:14:23 +08:00
|
|
|
}
|
|
|
|
|
2020-01-24 10:01:56 +08:00
|
|
|
if (rootProps != null && !isObject(rootProps)) {
|
|
|
|
__DEV__ && warn(`root props passed to app.mount() must be an object.`)
|
|
|
|
rootProps = null
|
|
|
|
}
|
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
const context = createAppContext()
|
2023-10-20 17:11:52 +08:00
|
|
|
const installedPlugins = new WeakSet()
|
2024-04-29 18:47:56 +08:00
|
|
|
const pluginCleanupFns: Array<() => any> = []
|
2019-09-03 04:09:34 +08:00
|
|
|
|
2019-09-04 06:11:04 +08:00
|
|
|
let isMounted = false
|
|
|
|
|
2020-07-21 09:51:30 +08:00
|
|
|
const app: App = (context.app = {
|
2020-09-01 06:32:07 +08:00
|
|
|
_uid: uid++,
|
2020-08-20 04:11:29 +08:00
|
|
|
_component: rootComponent as ConcreteComponent,
|
2020-01-24 10:01:56 +08:00
|
|
|
_props: rootProps,
|
|
|
|
_container: null,
|
2020-01-31 01:20:23 +08:00
|
|
|
_context: context,
|
2021-06-08 05:23:45 +08:00
|
|
|
_instance: null,
|
2020-01-24 04:05:38 +08:00
|
|
|
|
2020-06-26 21:03:55 +08:00
|
|
|
version,
|
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
get config() {
|
|
|
|
return context.config
|
|
|
|
},
|
|
|
|
|
|
|
|
set config(v) {
|
2019-09-03 04:16:08 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
warn(
|
|
|
|
`app.config cannot be replaced. Modify individual options instead.`,
|
|
|
|
)
|
|
|
|
}
|
2019-09-03 04:09:34 +08:00
|
|
|
},
|
|
|
|
|
2019-12-24 23:33:47 +08:00
|
|
|
use(plugin: Plugin, ...options: any[]) {
|
2019-11-05 23:49:00 +08:00
|
|
|
if (installedPlugins.has(plugin)) {
|
|
|
|
__DEV__ && warn(`Plugin has already been applied to target app.`)
|
2019-11-27 22:18:03 +08:00
|
|
|
} else if (plugin && isFunction(plugin.install)) {
|
2019-11-05 23:49:00 +08:00
|
|
|
installedPlugins.add(plugin)
|
2019-12-24 23:33:47 +08:00
|
|
|
plugin.install(app, ...options)
|
2020-01-09 01:40:24 +08:00
|
|
|
} else if (isFunction(plugin)) {
|
|
|
|
installedPlugins.add(plugin)
|
|
|
|
plugin(app, ...options)
|
2019-09-03 04:09:34 +08:00
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(
|
|
|
|
`A plugin must either be a function or an object with an "install" ` +
|
|
|
|
`function.`,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return app
|
|
|
|
},
|
|
|
|
|
|
|
|
mixin(mixin: ComponentOptions) {
|
2020-07-21 09:51:30 +08:00
|
|
|
if (__FEATURE_OPTIONS_API__) {
|
2020-02-16 00:40:09 +08:00
|
|
|
if (!context.mixins.includes(mixin)) {
|
|
|
|
context.mixins.push(mixin)
|
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(
|
|
|
|
'Mixin has already been applied to target app' +
|
|
|
|
(mixin.name ? `: ${mixin.name}` : ''),
|
|
|
|
)
|
|
|
|
}
|
2019-10-29 04:22:03 +08:00
|
|
|
} else if (__DEV__) {
|
2020-02-16 00:40:09 +08:00
|
|
|
warn('Mixins are only available in builds supporting Options API')
|
2019-10-29 04:22:03 +08:00
|
|
|
}
|
2019-09-03 04:09:34 +08:00
|
|
|
return app
|
|
|
|
},
|
|
|
|
|
2020-08-20 04:11:29 +08:00
|
|
|
component(name: string, component?: Component): any {
|
2019-10-15 03:36:30 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
validateComponentName(name, context.config)
|
|
|
|
}
|
2019-09-03 04:09:34 +08:00
|
|
|
if (!component) {
|
2019-10-11 02:54:06 +08:00
|
|
|
return context.components[name]
|
2019-09-03 04:09:34 +08:00
|
|
|
}
|
2019-11-27 22:18:03 +08:00
|
|
|
if (__DEV__ && context.components[name]) {
|
|
|
|
warn(`Component "${name}" has already been registered in target app.`)
|
|
|
|
}
|
2020-03-12 22:19:30 +08:00
|
|
|
context.components[name] = component
|
2019-11-27 22:18:03 +08:00
|
|
|
return app
|
2019-09-03 04:09:34 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
directive(name: string, directive?: Directive) {
|
2019-10-19 00:34:45 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
validateDirectiveName(name)
|
|
|
|
}
|
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
if (!directive) {
|
|
|
|
return context.directives[name] as any
|
|
|
|
}
|
2019-11-27 22:18:03 +08:00
|
|
|
if (__DEV__ && context.directives[name]) {
|
|
|
|
warn(`Directive "${name}" has already been registered in target app.`)
|
|
|
|
}
|
|
|
|
context.directives[name] = directive
|
|
|
|
return app
|
2019-09-03 04:09:34 +08:00
|
|
|
},
|
|
|
|
|
2021-03-02 00:51:32 +08:00
|
|
|
mount(
|
|
|
|
rootContainer: HostElement,
|
|
|
|
isHydrate?: boolean,
|
2023-12-08 18:25:01 +08:00
|
|
|
namespace?: boolean | ElementNamespace,
|
2021-03-02 00:51:32 +08:00
|
|
|
): any {
|
2019-09-04 06:11:04 +08:00
|
|
|
if (!isMounted) {
|
2022-05-13 09:09:18 +08:00
|
|
|
// #5571
|
|
|
|
if (__DEV__ && (rootContainer as any).__vue_app__) {
|
|
|
|
warn(
|
|
|
|
`There is already an app instance mounted on the host container.\n` +
|
|
|
|
` If you want to mount another app on the same host container,` +
|
|
|
|
` you need to unmount the previous app by calling \`app.unmount()\` first.`,
|
|
|
|
)
|
|
|
|
}
|
2024-08-07 16:07:47 +08:00
|
|
|
const vnode = app._ceVNode || createVNode(rootComponent, rootProps)
|
2019-09-04 06:11:04 +08:00
|
|
|
// store app context on the root VNode.
|
|
|
|
// this will be set on the root instance on initial mount.
|
|
|
|
vnode.appContext = context
|
2019-12-23 01:25:04 +08:00
|
|
|
|
2023-12-08 18:25:01 +08:00
|
|
|
if (namespace === true) {
|
|
|
|
namespace = 'svg'
|
|
|
|
} else if (namespace === false) {
|
|
|
|
namespace = undefined
|
|
|
|
}
|
|
|
|
|
2019-12-23 01:25:04 +08:00
|
|
|
// HMR root reload
|
2020-04-20 12:34:53 +08:00
|
|
|
if (__DEV__) {
|
2019-12-23 01:25:04 +08:00
|
|
|
context.reload = () => {
|
2023-12-08 18:25:01 +08:00
|
|
|
// casting to ElementNamespace because TS doesn't guarantee type narrowing
|
|
|
|
// over function boundaries
|
|
|
|
render(
|
|
|
|
cloneVNode(vnode),
|
|
|
|
rootContainer,
|
|
|
|
namespace as ElementNamespace,
|
|
|
|
)
|
2019-12-23 01:25:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 14:30:08 +08:00
|
|
|
if (isHydrate && hydrate) {
|
2020-03-23 23:08:22 +08:00
|
|
|
hydrate(vnode as VNode<Node, Element>, rootContainer as any)
|
2020-02-14 12:31:03 +08:00
|
|
|
} else {
|
2023-12-08 18:25:01 +08:00
|
|
|
render(vnode, rootContainer, namespace)
|
2020-02-14 12:31:03 +08:00
|
|
|
}
|
2019-09-04 06:11:04 +08:00
|
|
|
isMounted = true
|
2020-01-24 10:01:56 +08:00
|
|
|
app._container = rootContainer
|
2020-07-21 09:51:30 +08:00
|
|
|
// for devtools and telemetry
|
|
|
|
;(rootContainer as any).__vue_app__ = app
|
2020-07-17 06:18:52 +08:00
|
|
|
|
2020-07-21 09:51:30 +08:00
|
|
|
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
2021-06-08 05:23:45 +08:00
|
|
|
app._instance = vnode.component
|
2020-07-21 09:51:30 +08:00
|
|
|
devtoolsInitApp(app, version)
|
|
|
|
}
|
2020-07-17 06:18:52 +08:00
|
|
|
|
2024-06-10 17:37:32 +08:00
|
|
|
return getComponentPublicInstance(vnode.component!)
|
2019-09-04 06:11:04 +08:00
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(
|
2020-06-12 05:20:38 +08:00
|
|
|
`App has already been mounted.\n` +
|
|
|
|
`If you want to remount the same app, move your app creation logic ` +
|
|
|
|
`into a factory function and create fresh app instances for each ` +
|
|
|
|
`mount - e.g. \`const createMyApp = () => createApp(App)\``,
|
2019-09-04 06:11:04 +08:00
|
|
|
)
|
|
|
|
}
|
2019-09-03 04:09:34 +08:00
|
|
|
},
|
|
|
|
|
2024-04-29 18:47:56 +08:00
|
|
|
onUnmount(cleanupFn: () => void) {
|
|
|
|
if (__DEV__ && typeof cleanupFn !== 'function') {
|
|
|
|
warn(
|
|
|
|
`Expected function as first argument to app.onUnmount(), ` +
|
|
|
|
`but got ${typeof cleanupFn}`,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
pluginCleanupFns.push(cleanupFn)
|
|
|
|
},
|
|
|
|
|
2020-01-24 04:05:38 +08:00
|
|
|
unmount() {
|
|
|
|
if (isMounted) {
|
2024-04-29 18:47:56 +08:00
|
|
|
callWithAsyncErrorHandling(
|
|
|
|
pluginCleanupFns,
|
|
|
|
app._instance,
|
|
|
|
ErrorCodes.APP_UNMOUNT_CLEANUP,
|
|
|
|
)
|
2020-02-16 00:33:22 +08:00
|
|
|
render(null, app._container)
|
2020-08-22 22:34:18 +08:00
|
|
|
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
2021-06-08 05:23:45 +08:00
|
|
|
app._instance = null
|
2020-08-22 22:34:18 +08:00
|
|
|
devtoolsUnmountApp(app)
|
|
|
|
}
|
2021-02-04 02:09:20 +08:00
|
|
|
delete app._container.__vue_app__
|
2020-01-24 04:05:38 +08:00
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(`Cannot unmount an app that is not mounted.`)
|
|
|
|
}
|
2020-01-17 01:23:47 +08:00
|
|
|
},
|
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
provide(key, value) {
|
2020-08-21 05:48:28 +08:00
|
|
|
if (__DEV__ && (key as string | symbol) in context.provides) {
|
2019-09-03 04:09:34 +08:00
|
|
|
warn(
|
2020-05-02 22:26:32 +08:00
|
|
|
`App already provides property with key "${String(key)}". ` +
|
2019-09-03 04:09:34 +08:00
|
|
|
`It will be overwritten with the new value.`,
|
|
|
|
)
|
|
|
|
}
|
2022-05-06 18:44:28 +08:00
|
|
|
|
|
|
|
context.provides[key as string | symbol] = value
|
2019-10-28 08:54:33 +08:00
|
|
|
|
|
|
|
return app
|
2023-04-05 15:18:13 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
runWithContext(fn) {
|
2024-02-07 13:33:44 +08:00
|
|
|
const lastApp = currentApp
|
2023-04-05 15:18:13 +08:00
|
|
|
currentApp = app
|
|
|
|
try {
|
|
|
|
return fn()
|
|
|
|
} finally {
|
2024-02-07 13:33:44 +08:00
|
|
|
currentApp = lastApp
|
2023-04-05 15:18:13 +08:00
|
|
|
}
|
2019-09-03 04:09:34 +08:00
|
|
|
},
|
2020-07-21 09:51:30 +08:00
|
|
|
})
|
2020-07-17 06:18:52 +08:00
|
|
|
|
2021-04-05 23:54:35 +08:00
|
|
|
if (__COMPAT__) {
|
2021-05-07 05:15:11 +08:00
|
|
|
installAppCompatProperties(app, context, render)
|
2021-04-05 23:54:35 +08:00
|
|
|
}
|
|
|
|
|
2019-09-03 04:09:34 +08:00
|
|
|
return app
|
|
|
|
}
|
|
|
|
}
|
2023-04-05 15:18:13 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal Used to identify the current app when using `inject()` within
|
|
|
|
* `app.runWithContext()`.
|
|
|
|
*/
|
|
|
|
export let currentApp: App<unknown> | null = null
|