2019-09-04 10:25:38 +08:00
|
|
|
import {
|
2019-09-07 00:58:31 +08:00
|
|
|
ComponentInternalInstance,
|
2019-09-04 10:25:38 +08:00
|
|
|
Data,
|
2019-10-22 01:44:01 +08:00
|
|
|
SetupContext,
|
2020-06-09 23:27:40 +08:00
|
|
|
ComponentInternalOptions,
|
2020-07-28 05:44:17 +08:00
|
|
|
Component,
|
2020-08-20 04:11:29 +08:00
|
|
|
ConcreteComponent,
|
2020-07-28 05:44:17 +08:00
|
|
|
InternalRenderFunction
|
2019-09-04 10:25:38 +08:00
|
|
|
} from './component'
|
|
|
|
import {
|
|
|
|
isFunction,
|
|
|
|
extend,
|
|
|
|
isString,
|
|
|
|
isObject,
|
|
|
|
isArray,
|
2019-10-14 14:15:31 +08:00
|
|
|
EMPTY_OBJ,
|
2020-03-24 23:59:00 +08:00
|
|
|
NOOP,
|
2020-04-15 05:40:41 +08:00
|
|
|
hasOwn,
|
|
|
|
isPromise
|
2019-09-04 10:25:38 +08:00
|
|
|
} from '@vue/shared'
|
2020-02-14 13:13:54 +08:00
|
|
|
import { computed } from './apiComputed'
|
2019-12-31 00:30:12 +08:00
|
|
|
import { watch, WatchOptions, WatchCallback } from './apiWatch'
|
2019-09-04 10:25:38 +08:00
|
|
|
import { provide, inject } from './apiInject'
|
|
|
|
import {
|
|
|
|
onBeforeMount,
|
|
|
|
onMounted,
|
|
|
|
onBeforeUpdate,
|
|
|
|
onUpdated,
|
|
|
|
onErrorCaptured,
|
|
|
|
onRenderTracked,
|
|
|
|
onBeforeUnmount,
|
2019-10-02 21:46:29 +08:00
|
|
|
onUnmounted,
|
2019-10-30 10:28:38 +08:00
|
|
|
onActivated,
|
|
|
|
onDeactivated,
|
2019-10-15 11:15:09 +08:00
|
|
|
onRenderTriggered,
|
|
|
|
DebuggerHook,
|
|
|
|
ErrorCapturedHook
|
2019-09-04 10:25:38 +08:00
|
|
|
} from './apiLifecycle'
|
2019-10-22 01:57:20 +08:00
|
|
|
import {
|
|
|
|
reactive,
|
|
|
|
ComputedGetter,
|
2020-04-23 04:36:18 +08:00
|
|
|
WritableComputedOptions,
|
|
|
|
toRaw
|
2019-10-22 01:57:20 +08:00
|
|
|
} from '@vue/reactivity'
|
2020-09-01 06:32:07 +08:00
|
|
|
import { ComponentObjectPropsOptions, ExtractPropTypes } from './componentProps'
|
2020-04-04 07:08:17 +08:00
|
|
|
import { EmitsOptions } from './componentEmits'
|
2019-09-06 23:19:22 +08:00
|
|
|
import { Directive } from './directives'
|
2020-06-09 22:37:00 +08:00
|
|
|
import {
|
|
|
|
CreateComponentPublicInstance,
|
|
|
|
ComponentPublicInstance
|
2020-08-20 04:11:29 +08:00
|
|
|
} from './componentPublicInstance'
|
2019-10-02 22:03:43 +08:00
|
|
|
import { warn } from './warning'
|
2020-05-01 22:37:40 +08:00
|
|
|
import { VNodeChild } from './vnode'
|
2019-09-06 23:19:22 +08:00
|
|
|
|
2020-04-17 21:41:36 +08:00
|
|
|
/**
|
|
|
|
* Interface for declaring custom options.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```ts
|
|
|
|
* declare module '@vue/runtime-core' {
|
|
|
|
* interface ComponentCustomOptions {
|
|
|
|
* beforeRouteUpdate?(
|
|
|
|
* to: Route,
|
|
|
|
* from: Route,
|
|
|
|
* next: () => void
|
|
|
|
* ): void
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
export interface ComponentCustomOptions {}
|
|
|
|
|
2020-05-01 22:37:40 +08:00
|
|
|
export type RenderFunction = () => VNodeChild
|
|
|
|
|
2019-10-22 23:26:48 +08:00
|
|
|
export interface ComponentOptionsBase<
|
2019-09-06 23:19:22 +08:00
|
|
|
Props,
|
|
|
|
RawBindings,
|
|
|
|
D,
|
|
|
|
C extends ComputedOptions,
|
2020-04-04 00:05:52 +08:00
|
|
|
M extends MethodOptions,
|
2020-06-09 22:37:00 +08:00
|
|
|
Mixin extends ComponentOptionsMixin,
|
|
|
|
Extends extends ComponentOptionsMixin,
|
2020-04-04 00:05:52 +08:00
|
|
|
E extends EmitsOptions,
|
|
|
|
EE extends string = string
|
2020-04-17 21:41:36 +08:00
|
|
|
>
|
2020-06-09 22:37:00 +08:00
|
|
|
extends LegacyOptions<Props, D, C, M, Mixin, Extends>,
|
2020-06-09 23:27:40 +08:00
|
|
|
ComponentInternalOptions,
|
2020-04-17 21:41:36 +08:00
|
|
|
ComponentCustomOptions {
|
2019-09-06 23:19:22 +08:00
|
|
|
setup?: (
|
2020-01-11 00:46:34 +08:00
|
|
|
this: void,
|
2019-09-06 23:19:22 +08:00
|
|
|
props: Props,
|
2020-04-04 00:05:52 +08:00
|
|
|
ctx: SetupContext<E>
|
2019-10-22 01:44:01 +08:00
|
|
|
) => RawBindings | RenderFunction | void
|
2019-09-06 23:19:22 +08:00
|
|
|
name?: string
|
2019-12-11 23:39:29 +08:00
|
|
|
template?: string | object // can be a direct DOM node
|
2019-09-06 23:19:22 +08:00
|
|
|
// Note: we are intentionally using the signature-less `Function` type here
|
|
|
|
// since any type with signature will cause the whole inference to fail when
|
|
|
|
// the return expression contains reference to `this`.
|
|
|
|
// Luckily `render()` doesn't need any arguments nor does it care about return
|
|
|
|
// type.
|
|
|
|
render?: Function
|
2020-08-20 04:11:29 +08:00
|
|
|
components?: Record<string, Component>
|
2019-09-06 23:19:22 +08:00
|
|
|
directives?: Record<string, Directive>
|
2019-10-26 00:12:17 +08:00
|
|
|
inheritAttrs?: boolean
|
2020-08-15 05:36:26 +08:00
|
|
|
emits?: (E | EE[]) & ThisType<void>
|
2020-09-02 10:52:46 +08:00
|
|
|
serverPrefetch?(): Promise<any>
|
2019-11-01 00:43:05 +08:00
|
|
|
|
2020-03-24 23:59:00 +08:00
|
|
|
// Internal ------------------------------------------------------------------
|
|
|
|
|
2020-05-01 22:37:40 +08:00
|
|
|
/**
|
|
|
|
* SSR only. This is produced by compiler-ssr and attached in compiler-sfc
|
|
|
|
* not user facing, so the typing is lax and for test only.
|
|
|
|
*
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
ssrRender?: (
|
|
|
|
ctx: any,
|
|
|
|
push: (item: any) => void,
|
2020-06-27 02:23:50 +08:00
|
|
|
parentInstance: ComponentInternalInstance,
|
2020-07-11 10:12:25 +08:00
|
|
|
attrs: Data | undefined,
|
|
|
|
// for compiler-optimized bindings
|
|
|
|
$props: ComponentInternalInstance['props'],
|
|
|
|
$setup: ComponentInternalInstance['setupState'],
|
|
|
|
$data: ComponentInternalInstance['data'],
|
|
|
|
$options: ComponentInternalInstance['ctx']
|
2020-05-01 22:37:40 +08:00
|
|
|
) => void
|
|
|
|
|
|
|
|
/**
|
|
|
|
* marker for AsyncComponentWrapper
|
|
|
|
* @internal
|
|
|
|
*/
|
2020-08-20 04:11:29 +08:00
|
|
|
__asyncLoader?: () => Promise<ConcreteComponent>
|
2020-05-01 22:37:40 +08:00
|
|
|
/**
|
|
|
|
* cache for merged $options
|
|
|
|
* @internal
|
|
|
|
*/
|
2020-03-24 23:59:00 +08:00
|
|
|
__merged?: ComponentOptions
|
|
|
|
|
2020-05-01 22:37:40 +08:00
|
|
|
// Type differentiators ------------------------------------------------------
|
|
|
|
|
|
|
|
// Note these are internal but need to be exposed in d.ts for type inference
|
|
|
|
// to work!
|
|
|
|
|
2019-11-28 17:01:53 +08:00
|
|
|
// type-only differentiator to separate OptionWithoutProps from a constructor
|
2019-12-22 23:58:12 +08:00
|
|
|
// type returned by defineComponent() or FunctionalComponent
|
2020-06-09 22:17:42 +08:00
|
|
|
call?: (this: unknown, ...args: unknown[]) => never
|
2019-11-02 10:54:01 +08:00
|
|
|
// type-only differentiators for built-in Vnode types
|
|
|
|
__isFragment?: never
|
2020-03-31 22:52:42 +08:00
|
|
|
__isTeleport?: never
|
2019-11-02 10:54:01 +08:00
|
|
|
__isSuspense?: never
|
2019-09-06 23:19:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export type ComponentOptionsWithoutProps<
|
|
|
|
Props = {},
|
|
|
|
RawBindings = {},
|
|
|
|
D = {},
|
|
|
|
C extends ComputedOptions = {},
|
2020-04-04 00:05:52 +08:00
|
|
|
M extends MethodOptions = {},
|
2020-06-09 22:37:00 +08:00
|
|
|
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
|
|
|
|
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
|
2020-04-04 08:40:34 +08:00
|
|
|
E extends EmitsOptions = EmitsOptions,
|
2020-04-04 00:05:52 +08:00
|
|
|
EE extends string = string
|
2020-06-09 22:37:00 +08:00
|
|
|
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> & {
|
2019-09-06 23:19:22 +08:00
|
|
|
props?: undefined
|
2020-04-04 00:05:52 +08:00
|
|
|
} & ThisType<
|
2020-06-09 22:37:00 +08:00
|
|
|
CreateComponentPublicInstance<
|
|
|
|
{},
|
|
|
|
RawBindings,
|
|
|
|
D,
|
|
|
|
C,
|
|
|
|
M,
|
|
|
|
Mixin,
|
|
|
|
Extends,
|
|
|
|
E,
|
|
|
|
Readonly<Props>
|
|
|
|
>
|
2020-04-04 00:05:52 +08:00
|
|
|
>
|
2019-09-06 23:19:22 +08:00
|
|
|
|
|
|
|
export type ComponentOptionsWithArrayProps<
|
|
|
|
PropNames extends string = string,
|
|
|
|
RawBindings = {},
|
|
|
|
D = {},
|
|
|
|
C extends ComputedOptions = {},
|
|
|
|
M extends MethodOptions = {},
|
2020-06-09 22:37:00 +08:00
|
|
|
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
|
|
|
|
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
|
2020-04-04 08:40:34 +08:00
|
|
|
E extends EmitsOptions = EmitsOptions,
|
2020-04-04 00:05:52 +08:00
|
|
|
EE extends string = string,
|
2019-11-10 07:40:25 +08:00
|
|
|
Props = Readonly<{ [key in PropNames]?: any }>
|
2020-06-09 22:37:00 +08:00
|
|
|
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> & {
|
2019-09-06 23:19:22 +08:00
|
|
|
props: PropNames[]
|
2020-06-09 22:37:00 +08:00
|
|
|
} & ThisType<
|
|
|
|
CreateComponentPublicInstance<
|
|
|
|
Props,
|
|
|
|
RawBindings,
|
|
|
|
D,
|
|
|
|
C,
|
|
|
|
M,
|
|
|
|
Mixin,
|
|
|
|
Extends,
|
|
|
|
E
|
|
|
|
>
|
|
|
|
>
|
2019-09-06 23:19:22 +08:00
|
|
|
|
2019-10-08 21:26:09 +08:00
|
|
|
export type ComponentOptionsWithObjectProps<
|
|
|
|
PropsOptions = ComponentObjectPropsOptions,
|
2019-09-06 23:19:22 +08:00
|
|
|
RawBindings = {},
|
|
|
|
D = {},
|
|
|
|
C extends ComputedOptions = {},
|
|
|
|
M extends MethodOptions = {},
|
2020-06-09 22:37:00 +08:00
|
|
|
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
|
|
|
|
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
|
2020-04-04 08:40:34 +08:00
|
|
|
E extends EmitsOptions = EmitsOptions,
|
2020-04-04 00:05:52 +08:00
|
|
|
EE extends string = string,
|
2019-11-10 07:40:25 +08:00
|
|
|
Props = Readonly<ExtractPropTypes<PropsOptions>>
|
2020-06-09 22:37:00 +08:00
|
|
|
> = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E, EE> & {
|
2020-08-18 23:25:55 +08:00
|
|
|
props: PropsOptions & ThisType<void>
|
2020-06-09 22:37:00 +08:00
|
|
|
} & ThisType<
|
|
|
|
CreateComponentPublicInstance<
|
|
|
|
Props,
|
|
|
|
RawBindings,
|
|
|
|
D,
|
|
|
|
C,
|
|
|
|
M,
|
|
|
|
Mixin,
|
|
|
|
Extends,
|
|
|
|
E
|
|
|
|
>
|
|
|
|
>
|
2019-09-06 23:19:22 +08:00
|
|
|
|
|
|
|
export type ComponentOptions =
|
2020-03-23 23:08:22 +08:00
|
|
|
| ComponentOptionsWithoutProps<any, any, any, any, any>
|
|
|
|
| ComponentOptionsWithObjectProps<any, any, any, any, any>
|
|
|
|
| ComponentOptionsWithArrayProps<any, any, any, any, any>
|
2019-09-04 10:25:38 +08:00
|
|
|
|
2020-06-09 22:37:00 +08:00
|
|
|
export type ComponentOptionsMixin = ComponentOptionsBase<
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any,
|
|
|
|
any
|
|
|
|
>
|
|
|
|
|
2019-10-22 01:57:20 +08:00
|
|
|
export type ComputedOptions = Record<
|
|
|
|
string,
|
|
|
|
ComputedGetter<any> | WritableComputedOptions<any>
|
|
|
|
>
|
2019-09-06 04:09:30 +08:00
|
|
|
|
|
|
|
export interface MethodOptions {
|
|
|
|
[key: string]: Function
|
|
|
|
}
|
|
|
|
|
2019-10-05 22:38:02 +08:00
|
|
|
export type ExtractComputedReturns<T extends any> = {
|
2020-06-09 22:17:42 +08:00
|
|
|
[key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }
|
|
|
|
? TReturn
|
|
|
|
: T[key] extends (...args: any[]) => infer TReturn ? TReturn : never
|
2019-09-06 04:09:30 +08:00
|
|
|
}
|
|
|
|
|
2019-10-25 22:25:52 +08:00
|
|
|
type WatchOptionItem =
|
|
|
|
| string
|
2019-12-31 00:30:12 +08:00
|
|
|
| WatchCallback
|
2020-08-05 00:42:47 +08:00
|
|
|
| { handler: WatchCallback | string } & WatchOptions
|
2019-10-25 22:25:52 +08:00
|
|
|
|
|
|
|
type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]
|
|
|
|
|
|
|
|
type ComponentWatchOptions = Record<string, ComponentWatchOptionItem>
|
2019-09-06 23:19:22 +08:00
|
|
|
|
|
|
|
type ComponentInjectOptions =
|
|
|
|
| string[]
|
|
|
|
| Record<
|
|
|
|
string | symbol,
|
2019-10-22 23:26:48 +08:00
|
|
|
string | symbol | { from: string | symbol; default?: unknown }
|
2019-09-06 23:19:22 +08:00
|
|
|
>
|
|
|
|
|
2020-05-06 23:07:11 +08:00
|
|
|
interface LegacyOptions<
|
2019-09-06 04:09:30 +08:00
|
|
|
Props,
|
|
|
|
D,
|
|
|
|
C extends ComputedOptions,
|
2020-06-09 22:37:00 +08:00
|
|
|
M extends MethodOptions,
|
|
|
|
Mixin extends ComponentOptionsMixin,
|
|
|
|
Extends extends ComponentOptionsMixin
|
2019-09-06 04:09:30 +08:00
|
|
|
> {
|
2020-03-24 23:59:00 +08:00
|
|
|
// allow any custom options
|
|
|
|
[key: string]: any
|
2019-09-04 10:25:38 +08:00
|
|
|
|
|
|
|
// state
|
2019-09-06 23:19:22 +08:00
|
|
|
// Limitation: we cannot expose RawBindings on the `this` context for data
|
|
|
|
// since that leads to some sort of circular inference and breaks ThisType
|
|
|
|
// for the entire component.
|
2020-03-23 23:08:22 +08:00
|
|
|
data?: (
|
2020-06-09 22:37:00 +08:00
|
|
|
this: CreateComponentPublicInstance<Props>,
|
|
|
|
vm: CreateComponentPublicInstance<Props>
|
2020-03-23 23:08:22 +08:00
|
|
|
) => D
|
2019-09-06 06:48:49 +08:00
|
|
|
computed?: C
|
|
|
|
methods?: M
|
2019-09-06 23:19:22 +08:00
|
|
|
watch?: ComponentWatchOptions
|
2019-09-06 06:48:49 +08:00
|
|
|
provide?: Data | Function
|
2019-09-06 23:19:22 +08:00
|
|
|
inject?: ComponentInjectOptions
|
2019-09-04 10:25:38 +08:00
|
|
|
|
|
|
|
// composition
|
2020-06-09 22:37:00 +08:00
|
|
|
mixins?: Mixin[]
|
|
|
|
extends?: Extends
|
2019-09-04 10:25:38 +08:00
|
|
|
|
|
|
|
// lifecycle
|
2019-09-06 06:48:49 +08:00
|
|
|
beforeCreate?(): void
|
|
|
|
created?(): void
|
2019-09-04 10:25:38 +08:00
|
|
|
beforeMount?(): void
|
|
|
|
mounted?(): void
|
|
|
|
beforeUpdate?(): void
|
|
|
|
updated?(): void
|
|
|
|
activated?(): void
|
2019-10-05 22:48:54 +08:00
|
|
|
deactivated?(): void
|
2019-09-05 22:07:43 +08:00
|
|
|
beforeUnmount?(): void
|
|
|
|
unmounted?(): void
|
2019-10-15 11:15:09 +08:00
|
|
|
renderTracked?: DebuggerHook
|
|
|
|
renderTriggered?: DebuggerHook
|
|
|
|
errorCaptured?: ErrorCapturedHook
|
2020-07-23 09:29:59 +08:00
|
|
|
|
|
|
|
// runtime compile only
|
|
|
|
delimiters?: [string, string]
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
|
2020-06-09 22:37:00 +08:00
|
|
|
export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M'
|
|
|
|
|
|
|
|
export type OptionTypesType<
|
|
|
|
P = {},
|
|
|
|
B = {},
|
|
|
|
D = {},
|
|
|
|
C extends ComputedOptions = {},
|
|
|
|
M extends MethodOptions = {}
|
|
|
|
> = {
|
|
|
|
P: P
|
|
|
|
B: B
|
|
|
|
D: D
|
|
|
|
C: C
|
|
|
|
M: M
|
|
|
|
}
|
|
|
|
|
2019-10-22 11:47:16 +08:00
|
|
|
const enum OptionTypes {
|
|
|
|
PROPS = 'Props',
|
|
|
|
DATA = 'Data',
|
|
|
|
COMPUTED = 'Computed',
|
|
|
|
METHODS = 'Methods',
|
|
|
|
INJECT = 'Inject'
|
|
|
|
}
|
|
|
|
|
|
|
|
function createDuplicateChecker() {
|
|
|
|
const cache = Object.create(null)
|
|
|
|
return (type: OptionTypes, key: string) => {
|
|
|
|
if (cache[key]) {
|
|
|
|
warn(`${type} property "${key}" is already defined in ${cache[key]}.`)
|
|
|
|
} else {
|
|
|
|
cache[key] = type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 04:36:18 +08:00
|
|
|
type DataFn = (vm: ComponentPublicInstance) => any
|
|
|
|
|
2020-08-04 05:04:45 +08:00
|
|
|
export let isInBeforeCreate = false
|
|
|
|
|
2019-09-04 23:36:27 +08:00
|
|
|
export function applyOptions(
|
2019-09-07 00:58:31 +08:00
|
|
|
instance: ComponentInternalInstance,
|
2019-09-04 23:36:27 +08:00
|
|
|
options: ComponentOptions,
|
2020-04-23 04:36:18 +08:00
|
|
|
deferredData: DataFn[] = [],
|
|
|
|
deferredWatch: ComponentWatchOptions[] = [],
|
2019-09-04 23:36:27 +08:00
|
|
|
asMixin: boolean = false
|
|
|
|
) {
|
2019-09-04 10:25:38 +08:00
|
|
|
const {
|
2019-09-04 23:36:27 +08:00
|
|
|
// composition
|
|
|
|
mixins,
|
|
|
|
extends: extendsOptions,
|
|
|
|
// state
|
2019-09-04 10:25:38 +08:00
|
|
|
data: dataOptions,
|
|
|
|
computed: computedOptions,
|
|
|
|
methods,
|
|
|
|
watch: watchOptions,
|
|
|
|
provide: provideOptions,
|
|
|
|
inject: injectOptions,
|
2020-08-27 06:09:54 +08:00
|
|
|
// assets
|
|
|
|
components,
|
|
|
|
directives,
|
2019-09-04 23:36:27 +08:00
|
|
|
// lifecycle
|
2019-09-04 10:25:38 +08:00
|
|
|
beforeMount,
|
|
|
|
mounted,
|
|
|
|
beforeUpdate,
|
|
|
|
updated,
|
2019-10-30 10:28:38 +08:00
|
|
|
activated,
|
|
|
|
deactivated,
|
2019-09-05 22:07:43 +08:00
|
|
|
beforeUnmount,
|
|
|
|
unmounted,
|
2020-07-28 05:44:17 +08:00
|
|
|
render,
|
2019-09-04 10:25:38 +08:00
|
|
|
renderTracked,
|
|
|
|
renderTriggered,
|
|
|
|
errorCaptured
|
2019-09-04 23:36:27 +08:00
|
|
|
} = options
|
|
|
|
|
2020-04-23 04:36:18 +08:00
|
|
|
const publicThis = instance.proxy!
|
2020-04-17 00:49:50 +08:00
|
|
|
const ctx = instance.ctx
|
2019-09-05 22:07:43 +08:00
|
|
|
const globalMixins = instance.appContext.mixins
|
2020-07-28 05:44:17 +08:00
|
|
|
|
|
|
|
if (asMixin && render && instance.render === NOOP) {
|
|
|
|
instance.render = render as InternalRenderFunction
|
|
|
|
}
|
2020-04-06 06:39:22 +08:00
|
|
|
|
2019-09-06 08:59:45 +08:00
|
|
|
// applyOptions is called non-as-mixin once per instance
|
2019-09-05 22:07:43 +08:00
|
|
|
if (!asMixin) {
|
2020-08-04 05:04:45 +08:00
|
|
|
isInBeforeCreate = true
|
2020-04-17 00:49:50 +08:00
|
|
|
callSyncHook('beforeCreate', options, publicThis, globalMixins)
|
2020-08-04 05:04:45 +08:00
|
|
|
isInBeforeCreate = false
|
2019-09-06 08:59:45 +08:00
|
|
|
// global mixins are applied first
|
2020-04-23 04:36:18 +08:00
|
|
|
applyMixins(instance, globalMixins, deferredData, deferredWatch)
|
2019-09-04 23:36:27 +08:00
|
|
|
}
|
2020-07-28 05:44:17 +08:00
|
|
|
|
2019-09-04 23:36:27 +08:00
|
|
|
// extending a base component...
|
|
|
|
if (extendsOptions) {
|
2020-04-23 04:36:18 +08:00
|
|
|
applyOptions(instance, extendsOptions, deferredData, deferredWatch, true)
|
2019-09-04 23:36:27 +08:00
|
|
|
}
|
|
|
|
// local mixins
|
|
|
|
if (mixins) {
|
2020-04-23 04:36:18 +08:00
|
|
|
applyMixins(instance, mixins, deferredData, deferredWatch)
|
2019-09-04 23:36:27 +08:00
|
|
|
}
|
2019-09-04 10:25:38 +08:00
|
|
|
|
2020-04-06 06:39:22 +08:00
|
|
|
const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
|
|
|
|
|
2020-06-09 23:27:40 +08:00
|
|
|
if (__DEV__) {
|
2020-09-01 06:32:07 +08:00
|
|
|
const [propsOptions] = instance.propsOptions
|
2020-06-09 23:27:40 +08:00
|
|
|
if (propsOptions) {
|
|
|
|
for (const key in propsOptions) {
|
|
|
|
checkDuplicateProperties!(OptionTypes.PROPS, key)
|
|
|
|
}
|
2019-10-22 11:47:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 04:36:18 +08:00
|
|
|
// options initialization order (to be consistent with Vue 2):
|
|
|
|
// - props (already done outside of this function)
|
|
|
|
// - inject
|
|
|
|
// - methods
|
|
|
|
// - data (deferred since it relies on `this` access)
|
|
|
|
// - computed
|
|
|
|
// - watch (deferred since it relies on `this` access)
|
|
|
|
|
|
|
|
if (injectOptions) {
|
|
|
|
if (isArray(injectOptions)) {
|
|
|
|
for (let i = 0; i < injectOptions.length; i++) {
|
|
|
|
const key = injectOptions[i]
|
|
|
|
ctx[key] = inject(key)
|
|
|
|
if (__DEV__) {
|
|
|
|
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (const key in injectOptions) {
|
|
|
|
const opt = injectOptions[key]
|
|
|
|
if (isObject(opt)) {
|
|
|
|
ctx[key] = inject(opt.from, opt.default)
|
|
|
|
} else {
|
|
|
|
ctx[key] = inject(opt)
|
|
|
|
}
|
|
|
|
if (__DEV__) {
|
|
|
|
checkDuplicateProperties!(OptionTypes.INJECT, key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (methods) {
|
|
|
|
for (const key in methods) {
|
|
|
|
const methodHandler = (methods as MethodOptions)[key]
|
|
|
|
if (isFunction(methodHandler)) {
|
|
|
|
ctx[key] = methodHandler.bind(publicThis)
|
|
|
|
if (__DEV__) {
|
|
|
|
checkDuplicateProperties!(OptionTypes.METHODS, key)
|
|
|
|
}
|
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(
|
|
|
|
`Method "${key}" has type "${typeof methodHandler}" in the component definition. ` +
|
|
|
|
`Did you reference the function correctly?`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!asMixin) {
|
|
|
|
if (deferredData.length) {
|
|
|
|
deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis))
|
|
|
|
}
|
2020-08-25 09:30:04 +08:00
|
|
|
if (dataOptions) {
|
|
|
|
resolveData(instance, dataOptions, publicThis)
|
|
|
|
}
|
2020-04-23 04:36:18 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
const rawData = toRaw(instance.data)
|
|
|
|
for (const key in rawData) {
|
|
|
|
checkDuplicateProperties!(OptionTypes.DATA, key)
|
|
|
|
// expose data on ctx during dev
|
2020-05-01 23:23:01 +08:00
|
|
|
if (key[0] !== '$' && key[0] !== '_') {
|
|
|
|
Object.defineProperty(ctx, key, {
|
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
get: () => rawData[key],
|
|
|
|
set: NOOP
|
|
|
|
})
|
|
|
|
}
|
2019-10-22 11:47:16 +08:00
|
|
|
}
|
2019-10-02 22:03:43 +08:00
|
|
|
}
|
2020-08-25 09:30:04 +08:00
|
|
|
} else if (dataOptions) {
|
|
|
|
deferredData.push(dataOptions as DataFn)
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
2020-01-28 04:15:22 +08:00
|
|
|
|
2019-09-04 10:25:38 +08:00
|
|
|
if (computedOptions) {
|
|
|
|
for (const key in computedOptions) {
|
2019-09-06 04:09:30 +08:00
|
|
|
const opt = (computedOptions as ComputedOptions)[key]
|
2020-04-17 00:49:50 +08:00
|
|
|
const get = isFunction(opt)
|
|
|
|
? opt.bind(publicThis, publicThis)
|
|
|
|
: isFunction(opt.get)
|
|
|
|
? opt.get.bind(publicThis, publicThis)
|
|
|
|
: NOOP
|
|
|
|
if (__DEV__ && get === NOOP) {
|
|
|
|
warn(`Computed property "${key}" has no getter.`)
|
2019-10-14 14:15:31 +08:00
|
|
|
}
|
2020-04-17 00:49:50 +08:00
|
|
|
const set =
|
|
|
|
!isFunction(opt) && isFunction(opt.set)
|
|
|
|
? opt.set.bind(publicThis)
|
|
|
|
: __DEV__
|
|
|
|
? () => {
|
|
|
|
warn(
|
|
|
|
`Write operation failed: computed property "${key}" is readonly.`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
: NOOP
|
|
|
|
const c = computed({
|
|
|
|
get,
|
|
|
|
set
|
|
|
|
})
|
|
|
|
Object.defineProperty(ctx, key, {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
get: () => c.value,
|
|
|
|
set: v => (c.value = v)
|
|
|
|
})
|
2020-04-06 06:39:22 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
checkDuplicateProperties!(OptionTypes.COMPUTED, key)
|
|
|
|
}
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-22 11:47:16 +08:00
|
|
|
|
2019-09-04 10:25:38 +08:00
|
|
|
if (watchOptions) {
|
2020-04-23 04:36:18 +08:00
|
|
|
deferredWatch.push(watchOptions)
|
|
|
|
}
|
|
|
|
if (!asMixin && deferredWatch.length) {
|
|
|
|
deferredWatch.forEach(watchOptions => {
|
|
|
|
for (const key in watchOptions) {
|
|
|
|
createWatcher(watchOptions[key], ctx, publicThis, key)
|
|
|
|
}
|
|
|
|
})
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
2020-01-28 04:15:22 +08:00
|
|
|
|
2019-09-04 10:25:38 +08:00
|
|
|
if (provideOptions) {
|
|
|
|
const provides = isFunction(provideOptions)
|
2020-04-17 00:49:50 +08:00
|
|
|
? provideOptions.call(publicThis)
|
2019-09-04 10:25:38 +08:00
|
|
|
: provideOptions
|
|
|
|
for (const key in provides) {
|
|
|
|
provide(key, provides[key])
|
|
|
|
}
|
|
|
|
}
|
2020-01-28 04:15:22 +08:00
|
|
|
|
2020-08-27 06:09:54 +08:00
|
|
|
// asset options.
|
|
|
|
// To reduce memory usage, only components with mixins or extends will have
|
|
|
|
// resolved asset registry attached to instance.
|
|
|
|
if (asMixin) {
|
|
|
|
if (components) {
|
|
|
|
extend(
|
|
|
|
instance.components ||
|
|
|
|
(instance.components = extend(
|
|
|
|
{},
|
|
|
|
(instance.type as ComponentOptions).components
|
|
|
|
) as Record<string, ConcreteComponent>),
|
|
|
|
components
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (directives) {
|
|
|
|
extend(
|
|
|
|
instance.directives ||
|
|
|
|
(instance.directives = extend(
|
|
|
|
{},
|
|
|
|
(instance.type as ComponentOptions).directives
|
|
|
|
)),
|
|
|
|
directives
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-04 23:36:27 +08:00
|
|
|
// lifecycle options
|
2019-09-05 22:07:43 +08:00
|
|
|
if (!asMixin) {
|
2020-04-17 00:49:50 +08:00
|
|
|
callSyncHook('created', options, publicThis, globalMixins)
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
if (beforeMount) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onBeforeMount(beforeMount.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
if (mounted) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onMounted(mounted.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
if (beforeUpdate) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onBeforeUpdate(beforeUpdate.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
if (updated) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onUpdated(updated.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
2019-10-30 10:28:38 +08:00
|
|
|
if (activated) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onActivated(activated.bind(publicThis))
|
2019-10-30 10:28:38 +08:00
|
|
|
}
|
|
|
|
if (deactivated) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onDeactivated(deactivated.bind(publicThis))
|
2019-10-30 10:28:38 +08:00
|
|
|
}
|
2019-09-04 10:25:38 +08:00
|
|
|
if (errorCaptured) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onErrorCaptured(errorCaptured.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
if (renderTracked) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onRenderTracked(renderTracked.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
if (renderTriggered) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onRenderTriggered(renderTriggered.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
2019-09-05 22:07:43 +08:00
|
|
|
if (beforeUnmount) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onBeforeUnmount(beforeUnmount.bind(publicThis))
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
2019-09-05 22:07:43 +08:00
|
|
|
if (unmounted) {
|
2020-04-17 00:49:50 +08:00
|
|
|
onUnmounted(unmounted.bind(publicThis))
|
2019-09-05 22:07:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function callSyncHook(
|
|
|
|
name: 'beforeCreate' | 'created',
|
|
|
|
options: ComponentOptions,
|
2019-10-22 11:37:03 +08:00
|
|
|
ctx: ComponentPublicInstance,
|
2019-09-05 22:07:43 +08:00
|
|
|
globalMixins: ComponentOptions[]
|
|
|
|
) {
|
|
|
|
callHookFromMixins(name, globalMixins, ctx)
|
2020-08-26 22:31:23 +08:00
|
|
|
|
|
|
|
const { extends: base, mixins } = options
|
|
|
|
if (base) {
|
|
|
|
callHookFromExtends(name, base, ctx)
|
2019-09-05 22:07:43 +08:00
|
|
|
}
|
|
|
|
if (mixins) {
|
|
|
|
callHookFromMixins(name, mixins, ctx)
|
|
|
|
}
|
|
|
|
const selfHook = options[name]
|
|
|
|
if (selfHook) {
|
|
|
|
selfHook.call(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-26 22:31:23 +08:00
|
|
|
function callHookFromExtends(
|
|
|
|
name: 'beforeCreate' | 'created',
|
|
|
|
base: ComponentOptions,
|
|
|
|
ctx: ComponentPublicInstance
|
|
|
|
) {
|
|
|
|
if (base.extends) {
|
|
|
|
callHookFromExtends(name, base.extends, ctx)
|
|
|
|
}
|
|
|
|
const baseHook = base[name]
|
|
|
|
if (baseHook) {
|
|
|
|
baseHook.call(ctx)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-05 22:07:43 +08:00
|
|
|
function callHookFromMixins(
|
|
|
|
name: 'beforeCreate' | 'created',
|
|
|
|
mixins: ComponentOptions[],
|
2019-10-22 11:37:03 +08:00
|
|
|
ctx: ComponentPublicInstance
|
2019-09-05 22:07:43 +08:00
|
|
|
) {
|
|
|
|
for (let i = 0; i < mixins.length; i++) {
|
2020-08-26 22:31:23 +08:00
|
|
|
const chainedMixins = mixins[i].mixins
|
|
|
|
if (chainedMixins) {
|
|
|
|
callHookFromMixins(name, chainedMixins, ctx)
|
|
|
|
}
|
2019-09-05 22:07:43 +08:00
|
|
|
const fn = mixins[i][name]
|
|
|
|
if (fn) {
|
|
|
|
fn.call(ctx)
|
|
|
|
}
|
2019-09-04 10:25:38 +08:00
|
|
|
}
|
|
|
|
}
|
2019-09-04 11:04:11 +08:00
|
|
|
|
2019-09-07 00:58:31 +08:00
|
|
|
function applyMixins(
|
|
|
|
instance: ComponentInternalInstance,
|
2020-04-23 04:36:18 +08:00
|
|
|
mixins: ComponentOptions[],
|
|
|
|
deferredData: DataFn[],
|
|
|
|
deferredWatch: ComponentWatchOptions[]
|
2019-09-07 00:58:31 +08:00
|
|
|
) {
|
2019-09-04 23:36:27 +08:00
|
|
|
for (let i = 0; i < mixins.length; i++) {
|
2020-04-23 04:36:18 +08:00
|
|
|
applyOptions(instance, mixins[i], deferredData, deferredWatch, true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function resolveData(
|
|
|
|
instance: ComponentInternalInstance,
|
|
|
|
dataFn: DataFn,
|
|
|
|
publicThis: ComponentPublicInstance
|
|
|
|
) {
|
2020-08-25 09:30:04 +08:00
|
|
|
if (__DEV__ && !isFunction(dataFn)) {
|
|
|
|
warn(
|
|
|
|
`The data option must be a function. ` +
|
|
|
|
`Plain object usage is no longer supported.`
|
|
|
|
)
|
|
|
|
}
|
2020-04-23 04:36:18 +08:00
|
|
|
const data = dataFn.call(publicThis, publicThis)
|
|
|
|
if (__DEV__ && isPromise(data)) {
|
|
|
|
warn(
|
|
|
|
`data() returned a Promise - note data() cannot be async; If you ` +
|
|
|
|
`intend to perform data fetching before component renders, use ` +
|
|
|
|
`async setup() + <Suspense>.`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (!isObject(data)) {
|
|
|
|
__DEV__ && warn(`data() should return an object.`)
|
|
|
|
} else if (instance.data === EMPTY_OBJ) {
|
|
|
|
instance.data = reactive(data)
|
|
|
|
} else {
|
|
|
|
// existing data: this is a mixin or extends.
|
|
|
|
extend(instance.data, data)
|
2019-09-04 23:36:27 +08:00
|
|
|
}
|
|
|
|
}
|
2019-10-25 22:25:52 +08:00
|
|
|
|
|
|
|
function createWatcher(
|
|
|
|
raw: ComponentWatchOptionItem,
|
2020-04-17 00:49:50 +08:00
|
|
|
ctx: Data,
|
|
|
|
publicThis: ComponentPublicInstance,
|
2019-10-25 22:25:52 +08:00
|
|
|
key: string
|
|
|
|
) {
|
2020-04-17 21:12:50 +08:00
|
|
|
const getter = () => (publicThis as any)[key]
|
2019-10-25 22:25:52 +08:00
|
|
|
if (isString(raw)) {
|
2020-04-17 00:49:50 +08:00
|
|
|
const handler = ctx[raw]
|
2019-10-25 22:25:52 +08:00
|
|
|
if (isFunction(handler)) {
|
2019-12-31 00:30:12 +08:00
|
|
|
watch(getter, handler as WatchCallback)
|
2019-10-25 22:25:52 +08:00
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(`Invalid watch handler specified by key "${raw}"`, handler)
|
|
|
|
}
|
|
|
|
} else if (isFunction(raw)) {
|
2020-04-17 00:49:50 +08:00
|
|
|
watch(getter, raw.bind(publicThis))
|
2019-10-25 22:25:52 +08:00
|
|
|
} else if (isObject(raw)) {
|
|
|
|
if (isArray(raw)) {
|
2020-04-17 00:49:50 +08:00
|
|
|
raw.forEach(r => createWatcher(r, ctx, publicThis, key))
|
2019-10-25 22:25:52 +08:00
|
|
|
} else {
|
2020-08-05 00:42:47 +08:00
|
|
|
const handler = isFunction(raw.handler)
|
|
|
|
? raw.handler.bind(publicThis)
|
|
|
|
: (ctx[raw.handler] as WatchCallback)
|
|
|
|
if (isFunction(handler)) {
|
|
|
|
watch(getter, handler, raw)
|
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(`Invalid watch handler specified by key "${raw.handler}"`, handler)
|
|
|
|
}
|
2019-10-25 22:25:52 +08:00
|
|
|
}
|
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(`Invalid watch option: "${key}"`)
|
|
|
|
}
|
|
|
|
}
|
2020-03-24 23:59:00 +08:00
|
|
|
|
|
|
|
export function resolveMergedOptions(
|
|
|
|
instance: ComponentInternalInstance
|
|
|
|
): ComponentOptions {
|
|
|
|
const raw = instance.type as ComponentOptions
|
|
|
|
const { __merged, mixins, extends: extendsOptions } = raw
|
|
|
|
if (__merged) return __merged
|
|
|
|
const globalMixins = instance.appContext.mixins
|
2020-03-25 00:59:33 +08:00
|
|
|
if (!globalMixins.length && !mixins && !extendsOptions) return raw
|
2020-03-24 23:59:00 +08:00
|
|
|
const options = {}
|
2020-09-01 09:04:06 +08:00
|
|
|
globalMixins.forEach(m => mergeOptions(options, m, instance))
|
2020-09-03 22:35:43 +08:00
|
|
|
mergeOptions(options, raw, instance)
|
2020-03-24 23:59:00 +08:00
|
|
|
return (raw.__merged = options)
|
|
|
|
}
|
|
|
|
|
|
|
|
function mergeOptions(to: any, from: any, instance: ComponentInternalInstance) {
|
|
|
|
const strats = instance.appContext.config.optionMergeStrategies
|
2020-09-03 22:35:43 +08:00
|
|
|
const { mixins, extends: extendsOptions } = from
|
|
|
|
|
|
|
|
extendsOptions && mergeOptions(to, extendsOptions, instance)
|
|
|
|
mixins &&
|
|
|
|
mixins.forEach((m: ComponentOptionsMixin) => mergeOptions(to, m, instance))
|
|
|
|
|
2020-03-24 23:59:00 +08:00
|
|
|
for (const key in from) {
|
2020-07-02 08:12:47 +08:00
|
|
|
if (strats && hasOwn(strats, key)) {
|
|
|
|
to[key] = strats[key](to[key], from[key], instance.proxy, key)
|
2020-09-03 22:35:43 +08:00
|
|
|
} else {
|
2020-03-24 23:59:00 +08:00
|
|
|
to[key] = from[key]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|