componentOptions.ts 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. import type {
  2. Component,
  3. ComponentInternalInstance,
  4. ComponentInternalOptions,
  5. ConcreteComponent,
  6. Data,
  7. InternalRenderFunction,
  8. SetupContext,
  9. } from './component'
  10. import {
  11. type LooseRequired,
  12. NOOP,
  13. type Prettify,
  14. extend,
  15. isArray,
  16. isFunction,
  17. isObject,
  18. isPromise,
  19. isString,
  20. } from '@vue/shared'
  21. import { type Ref, isRef } from '@vue/reactivity'
  22. import { computed } from './apiComputed'
  23. import {
  24. type WatchCallback,
  25. type WatchOptions,
  26. createPathGetter,
  27. watch,
  28. } from './apiWatch'
  29. import { inject, provide } from './apiInject'
  30. import {
  31. type DebuggerHook,
  32. type ErrorCapturedHook,
  33. onActivated,
  34. onBeforeMount,
  35. onBeforeUnmount,
  36. onBeforeUpdate,
  37. onDeactivated,
  38. onErrorCaptured,
  39. onMounted,
  40. onRenderTracked,
  41. onRenderTriggered,
  42. onServerPrefetch,
  43. onUnmounted,
  44. onUpdated,
  45. } from './apiLifecycle'
  46. import {
  47. type ComputedGetter,
  48. type WritableComputedOptions,
  49. reactive,
  50. } from '@vue/reactivity'
  51. import type {
  52. ComponentObjectPropsOptions,
  53. ComponentPropsOptions,
  54. ExtractDefaultPropTypes,
  55. ExtractPropTypes,
  56. } from './componentProps'
  57. import type {
  58. EmitsOptions,
  59. EmitsToProps,
  60. TypeEmitsToOptions,
  61. } from './componentEmits'
  62. import type { Directive } from './directives'
  63. import {
  64. type ComponentPublicInstance,
  65. type CreateComponentPublicInstanceWithMixins,
  66. type IntersectionMixin,
  67. type UnwrapMixinsType,
  68. isReservedPrefix,
  69. } from './componentPublicInstance'
  70. import { warn } from './warning'
  71. import type { VNodeChild } from './vnode'
  72. import { callWithAsyncErrorHandling } from './errorHandling'
  73. import { deepMergeData } from './compat/data'
  74. import { DeprecationTypes } from './compat/compatConfig'
  75. import {
  76. type CompatConfig,
  77. isCompatEnabled,
  78. softAssertCompatEnabled,
  79. } from './compat/compatConfig'
  80. import type { OptionMergeFunction } from './apiCreateApp'
  81. import { LifecycleHooks } from './enums'
  82. import type { SlotsType } from './componentSlots'
  83. import {
  84. type ComponentTypeEmits,
  85. normalizePropsOrEmits,
  86. } from './apiSetupHelpers'
  87. import { markAsyncBoundary } from './helpers/useId'
  88. /**
  89. * Interface for declaring custom options.
  90. *
  91. * @example
  92. * ```ts
  93. * declare module 'vue' {
  94. * interface ComponentCustomOptions {
  95. * beforeRouteUpdate?(
  96. * to: Route,
  97. * from: Route,
  98. * next: () => void
  99. * ): void
  100. * }
  101. * }
  102. * ```
  103. */
  104. export interface ComponentCustomOptions {}
  105. export type RenderFunction = () => VNodeChild
  106. export interface ComponentOptionsBase<
  107. Props,
  108. RawBindings,
  109. D,
  110. C extends ComputedOptions,
  111. M extends MethodOptions,
  112. Mixin extends ComponentOptionsMixin,
  113. Extends extends ComponentOptionsMixin,
  114. E extends EmitsOptions,
  115. EE extends string = string,
  116. Defaults = {},
  117. I extends ComponentInjectOptions = {},
  118. II extends string = string,
  119. S extends SlotsType = {},
  120. LC extends Record<string, Component> = {},
  121. Directives extends Record<string, Directive> = {},
  122. Exposed extends string = string,
  123. Provide extends ComponentProvideOptions = ComponentProvideOptions,
  124. > extends LegacyOptions<Props, D, C, M, Mixin, Extends, I, II, Provide>,
  125. ComponentInternalOptions,
  126. ComponentCustomOptions {
  127. setup?: (
  128. this: void,
  129. props: LooseRequired<
  130. Props &
  131. Prettify<
  132. UnwrapMixinsType<
  133. IntersectionMixin<Mixin> & IntersectionMixin<Extends>,
  134. 'P'
  135. >
  136. >
  137. >,
  138. ctx: SetupContext<E, S>,
  139. ) => Promise<RawBindings> | RawBindings | RenderFunction | void
  140. name?: string
  141. template?: string | object // can be a direct DOM node
  142. // Note: we are intentionally using the signature-less `Function` type here
  143. // since any type with signature will cause the whole inference to fail when
  144. // the return expression contains reference to `this`.
  145. // Luckily `render()` doesn't need any arguments nor does it care about return
  146. // type.
  147. render?: Function
  148. // NOTE: extending both LC and Record<string, Component> allows objects to be forced
  149. // to be of type Component, while still inferring LC generic
  150. components?: LC & Record<string, Component>
  151. // NOTE: extending both Directives and Record<string, Directive> allows objects to be forced
  152. // to be of type Directive, while still inferring Directives generic
  153. directives?: Directives & Record<string, Directive>
  154. inheritAttrs?: boolean
  155. emits?: (E | EE[]) & ThisType<void>
  156. slots?: S
  157. expose?: Exposed[]
  158. serverPrefetch?(): void | Promise<any>
  159. // Runtime compiler only -----------------------------------------------------
  160. compilerOptions?: RuntimeCompilerOptions
  161. // Internal ------------------------------------------------------------------
  162. /**
  163. * SSR only. This is produced by compiler-ssr and attached in compiler-sfc
  164. * not user facing, so the typing is lax and for test only.
  165. * @internal
  166. */
  167. ssrRender?: (
  168. ctx: any,
  169. push: (item: any) => void,
  170. parentInstance: ComponentInternalInstance,
  171. attrs: Data | undefined,
  172. // for compiler-optimized bindings
  173. $props: ComponentInternalInstance['props'],
  174. $setup: ComponentInternalInstance['setupState'],
  175. $data: ComponentInternalInstance['data'],
  176. $options: ComponentInternalInstance['ctx'],
  177. ) => void
  178. /**
  179. * Only generated by compiler-sfc to mark a ssr render function inlined and
  180. * returned from setup()
  181. * @internal
  182. */
  183. __ssrInlineRender?: boolean
  184. /**
  185. * marker for AsyncComponentWrapper
  186. * @internal
  187. */
  188. __asyncLoader?: () => Promise<ConcreteComponent>
  189. /**
  190. * the inner component resolved by the AsyncComponentWrapper
  191. * @internal
  192. */
  193. __asyncResolved?: ConcreteComponent
  194. /**
  195. * Exposed for lazy hydration
  196. * @internal
  197. */
  198. __asyncHydrate?: (
  199. el: Element,
  200. instance: ComponentInternalInstance,
  201. hydrate: () => void,
  202. ) => void
  203. // Type differentiators ------------------------------------------------------
  204. // Note these are internal but need to be exposed in d.ts for type inference
  205. // to work!
  206. // type-only differentiator to separate OptionWithoutProps from a constructor
  207. // type returned by defineComponent() or FunctionalComponent
  208. call?: (this: unknown, ...args: unknown[]) => never
  209. // type-only differentiators for built-in Vnode types
  210. __isFragment?: never
  211. __isTeleport?: never
  212. __isSuspense?: never
  213. __defaults?: Defaults
  214. }
  215. /**
  216. * Subset of compiler options that makes sense for the runtime.
  217. */
  218. export interface RuntimeCompilerOptions {
  219. isCustomElement?: (tag: string) => boolean
  220. whitespace?: 'preserve' | 'condense'
  221. comments?: boolean
  222. delimiters?: [string, string]
  223. }
  224. export type ComponentOptions<
  225. Props = {},
  226. RawBindings = any,
  227. D = any,
  228. C extends ComputedOptions = any,
  229. M extends MethodOptions = any,
  230. Mixin extends ComponentOptionsMixin = any,
  231. Extends extends ComponentOptionsMixin = any,
  232. E extends EmitsOptions = any,
  233. EE extends string = string,
  234. Defaults = {},
  235. I extends ComponentInjectOptions = {},
  236. II extends string = string,
  237. S extends SlotsType = {},
  238. LC extends Record<string, Component> = {},
  239. Directives extends Record<string, Directive> = {},
  240. Exposed extends string = string,
  241. Provide extends ComponentProvideOptions = ComponentProvideOptions,
  242. > = ComponentOptionsBase<
  243. Props,
  244. RawBindings,
  245. D,
  246. C,
  247. M,
  248. Mixin,
  249. Extends,
  250. E,
  251. EE,
  252. Defaults,
  253. I,
  254. II,
  255. S,
  256. LC,
  257. Directives,
  258. Exposed,
  259. Provide
  260. > &
  261. ThisType<
  262. CreateComponentPublicInstanceWithMixins<
  263. {},
  264. RawBindings,
  265. D,
  266. C,
  267. M,
  268. Mixin,
  269. Extends,
  270. E,
  271. Readonly<Props>,
  272. Defaults,
  273. false,
  274. I,
  275. S,
  276. LC,
  277. Directives
  278. >
  279. >
  280. export type ComponentOptionsMixin = ComponentOptionsBase<
  281. any,
  282. any,
  283. any,
  284. any,
  285. any,
  286. any,
  287. any,
  288. any,
  289. any,
  290. any,
  291. any,
  292. any,
  293. any,
  294. any,
  295. any,
  296. any,
  297. any
  298. >
  299. export type ComputedOptions = Record<
  300. string,
  301. ComputedGetter<any> | WritableComputedOptions<any>
  302. >
  303. export interface MethodOptions {
  304. [key: string]: Function
  305. }
  306. export type ExtractComputedReturns<T extends any> = {
  307. [key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }
  308. ? TReturn
  309. : T[key] extends (...args: any[]) => infer TReturn
  310. ? TReturn
  311. : never
  312. }
  313. export type ObjectWatchOptionItem = {
  314. handler: WatchCallback | string
  315. } & WatchOptions
  316. type WatchOptionItem = string | WatchCallback | ObjectWatchOptionItem
  317. type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]
  318. type ComponentWatchOptions = Record<string, ComponentWatchOptionItem>
  319. export type ComponentProvideOptions = ObjectProvideOptions | Function
  320. type ObjectProvideOptions = Record<string | symbol, unknown>
  321. export type ComponentInjectOptions = string[] | ObjectInjectOptions
  322. type ObjectInjectOptions = Record<
  323. string | symbol,
  324. string | symbol | { from?: string | symbol; default?: unknown }
  325. >
  326. export type InjectToObject<T extends ComponentInjectOptions> =
  327. T extends string[]
  328. ? {
  329. [K in T[number]]?: unknown
  330. }
  331. : T extends ObjectInjectOptions
  332. ? {
  333. [K in keyof T]?: unknown
  334. }
  335. : never
  336. interface LegacyOptions<
  337. Props,
  338. D,
  339. C extends ComputedOptions,
  340. M extends MethodOptions,
  341. Mixin extends ComponentOptionsMixin,
  342. Extends extends ComponentOptionsMixin,
  343. I extends ComponentInjectOptions,
  344. II extends string,
  345. Provide extends ComponentProvideOptions = ComponentProvideOptions,
  346. > {
  347. compatConfig?: CompatConfig
  348. // allow any custom options
  349. [key: string]: any
  350. // state
  351. // Limitation: we cannot expose RawBindings on the `this` context for data
  352. // since that leads to some sort of circular inference and breaks ThisType
  353. // for the entire component.
  354. data?: (
  355. this: CreateComponentPublicInstanceWithMixins<
  356. Props,
  357. {},
  358. {},
  359. {},
  360. MethodOptions,
  361. Mixin,
  362. Extends
  363. >,
  364. vm: CreateComponentPublicInstanceWithMixins<
  365. Props,
  366. {},
  367. {},
  368. {},
  369. MethodOptions,
  370. Mixin,
  371. Extends
  372. >,
  373. ) => D
  374. computed?: C
  375. methods?: M
  376. watch?: ComponentWatchOptions
  377. provide?: Provide
  378. inject?: I | II[]
  379. // assets
  380. filters?: Record<string, Function>
  381. // composition
  382. mixins?: Mixin[]
  383. extends?: Extends
  384. // lifecycle
  385. beforeCreate?(): void
  386. created?(): void
  387. beforeMount?(): void
  388. mounted?(): void
  389. beforeUpdate?(): void
  390. updated?(): void
  391. activated?(): void
  392. deactivated?(): void
  393. /** @deprecated use `beforeUnmount` instead */
  394. beforeDestroy?(): void
  395. beforeUnmount?(): void
  396. /** @deprecated use `unmounted` instead */
  397. destroyed?(): void
  398. unmounted?(): void
  399. renderTracked?: DebuggerHook
  400. renderTriggered?: DebuggerHook
  401. errorCaptured?: ErrorCapturedHook
  402. /**
  403. * runtime compile only
  404. * @deprecated use `compilerOptions.delimiters` instead.
  405. */
  406. delimiters?: [string, string]
  407. /**
  408. * #3468
  409. *
  410. * type-only, used to assist Mixin's type inference,
  411. * typescript will try to simplify the inferred `Mixin` type,
  412. * with the `__differentiator`, typescript won't be able to combine different mixins,
  413. * because the `__differentiator` will be different
  414. */
  415. __differentiator?: keyof D | keyof C | keyof M
  416. }
  417. type MergedHook<T = () => void> = T | T[]
  418. export type MergedComponentOptions = ComponentOptions &
  419. MergedComponentOptionsOverride
  420. export type MergedComponentOptionsOverride = {
  421. beforeCreate?: MergedHook
  422. created?: MergedHook
  423. beforeMount?: MergedHook
  424. mounted?: MergedHook
  425. beforeUpdate?: MergedHook
  426. updated?: MergedHook
  427. activated?: MergedHook
  428. deactivated?: MergedHook
  429. /** @deprecated use `beforeUnmount` instead */
  430. beforeDestroy?: MergedHook
  431. beforeUnmount?: MergedHook
  432. /** @deprecated use `unmounted` instead */
  433. destroyed?: MergedHook
  434. unmounted?: MergedHook
  435. renderTracked?: MergedHook<DebuggerHook>
  436. renderTriggered?: MergedHook<DebuggerHook>
  437. errorCaptured?: MergedHook<ErrorCapturedHook>
  438. }
  439. export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'Defaults'
  440. export type OptionTypesType<
  441. P = {},
  442. B = {},
  443. D = {},
  444. C extends ComputedOptions = {},
  445. M extends MethodOptions = {},
  446. Defaults = {},
  447. > = {
  448. P: P
  449. B: B
  450. D: D
  451. C: C
  452. M: M
  453. Defaults: Defaults
  454. }
  455. enum OptionTypes {
  456. PROPS = 'Props',
  457. DATA = 'Data',
  458. COMPUTED = 'Computed',
  459. METHODS = 'Methods',
  460. INJECT = 'Inject',
  461. }
  462. function createDuplicateChecker() {
  463. const cache = Object.create(null)
  464. return (type: OptionTypes, key: string) => {
  465. if (cache[key]) {
  466. warn(`${type} property "${key}" is already defined in ${cache[key]}.`)
  467. } else {
  468. cache[key] = type
  469. }
  470. }
  471. }
  472. export let shouldCacheAccess = true
  473. export function applyOptions(instance: ComponentInternalInstance): void {
  474. const options = resolveMergedOptions(instance)
  475. const publicThis = instance.proxy! as any
  476. const ctx = instance.ctx
  477. // do not cache property access on public proxy during state initialization
  478. shouldCacheAccess = false
  479. // call beforeCreate first before accessing other options since
  480. // the hook may mutate resolved options (#2791)
  481. if (options.beforeCreate) {
  482. callHook(options.beforeCreate, instance, LifecycleHooks.BEFORE_CREATE)
  483. }
  484. const {
  485. // state
  486. data: dataOptions,
  487. computed: computedOptions,
  488. methods,
  489. watch: watchOptions,
  490. provide: provideOptions,
  491. inject: injectOptions,
  492. // lifecycle
  493. created,
  494. beforeMount,
  495. mounted,
  496. beforeUpdate,
  497. updated,
  498. activated,
  499. deactivated,
  500. beforeDestroy,
  501. beforeUnmount,
  502. destroyed,
  503. unmounted,
  504. render,
  505. renderTracked,
  506. renderTriggered,
  507. errorCaptured,
  508. serverPrefetch,
  509. // public API
  510. expose,
  511. inheritAttrs,
  512. // assets
  513. components,
  514. directives,
  515. filters,
  516. } = options
  517. const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
  518. if (__DEV__) {
  519. const [propsOptions] = instance.propsOptions
  520. if (propsOptions) {
  521. for (const key in propsOptions) {
  522. checkDuplicateProperties!(OptionTypes.PROPS, key)
  523. }
  524. }
  525. }
  526. // options initialization order (to be consistent with Vue 2):
  527. // - props (already done outside of this function)
  528. // - inject
  529. // - methods
  530. // - data (deferred since it relies on `this` access)
  531. // - computed
  532. // - watch (deferred since it relies on `this` access)
  533. if (injectOptions) {
  534. resolveInjections(injectOptions, ctx, checkDuplicateProperties)
  535. }
  536. if (methods) {
  537. for (const key in methods) {
  538. const methodHandler = (methods as MethodOptions)[key]
  539. if (isFunction(methodHandler)) {
  540. // In dev mode, we use the `createRenderContext` function to define
  541. // methods to the proxy target, and those are read-only but
  542. // reconfigurable, so it needs to be redefined here
  543. if (__DEV__) {
  544. Object.defineProperty(ctx, key, {
  545. value: methodHandler.bind(publicThis),
  546. configurable: true,
  547. enumerable: true,
  548. writable: true,
  549. })
  550. } else {
  551. ctx[key] = methodHandler.bind(publicThis)
  552. }
  553. if (__DEV__) {
  554. checkDuplicateProperties!(OptionTypes.METHODS, key)
  555. }
  556. } else if (__DEV__) {
  557. warn(
  558. `Method "${key}" has type "${typeof methodHandler}" in the component definition. ` +
  559. `Did you reference the function correctly?`,
  560. )
  561. }
  562. }
  563. }
  564. if (dataOptions) {
  565. if (__DEV__ && !isFunction(dataOptions)) {
  566. warn(
  567. `The data option must be a function. ` +
  568. `Plain object usage is no longer supported.`,
  569. )
  570. }
  571. const data = dataOptions.call(publicThis, publicThis)
  572. if (__DEV__ && isPromise(data)) {
  573. warn(
  574. `data() returned a Promise - note data() cannot be async; If you ` +
  575. `intend to perform data fetching before component renders, use ` +
  576. `async setup() + <Suspense>.`,
  577. )
  578. }
  579. if (!isObject(data)) {
  580. __DEV__ && warn(`data() should return an object.`)
  581. } else {
  582. instance.data = reactive(data)
  583. if (__DEV__) {
  584. for (const key in data) {
  585. checkDuplicateProperties!(OptionTypes.DATA, key)
  586. // expose data on ctx during dev
  587. if (!isReservedPrefix(key[0])) {
  588. Object.defineProperty(ctx, key, {
  589. configurable: true,
  590. enumerable: true,
  591. get: () => data[key],
  592. set: NOOP,
  593. })
  594. }
  595. }
  596. }
  597. }
  598. }
  599. // state initialization complete at this point - start caching access
  600. shouldCacheAccess = true
  601. if (computedOptions) {
  602. for (const key in computedOptions) {
  603. const opt = (computedOptions as ComputedOptions)[key]
  604. const get = isFunction(opt)
  605. ? opt.bind(publicThis, publicThis)
  606. : isFunction(opt.get)
  607. ? opt.get.bind(publicThis, publicThis)
  608. : NOOP
  609. if (__DEV__ && get === NOOP) {
  610. warn(`Computed property "${key}" has no getter.`)
  611. }
  612. const set =
  613. !isFunction(opt) && isFunction(opt.set)
  614. ? opt.set.bind(publicThis)
  615. : __DEV__
  616. ? () => {
  617. warn(
  618. `Write operation failed: computed property "${key}" is readonly.`,
  619. )
  620. }
  621. : NOOP
  622. const c = computed({
  623. get,
  624. set,
  625. })
  626. Object.defineProperty(ctx, key, {
  627. enumerable: true,
  628. configurable: true,
  629. get: () => c.value,
  630. set: v => (c.value = v),
  631. })
  632. if (__DEV__) {
  633. checkDuplicateProperties!(OptionTypes.COMPUTED, key)
  634. }
  635. }
  636. }
  637. if (watchOptions) {
  638. for (const key in watchOptions) {
  639. createWatcher(watchOptions[key], ctx, publicThis, key)
  640. }
  641. }
  642. if (provideOptions) {
  643. const provides = isFunction(provideOptions)
  644. ? provideOptions.call(publicThis)
  645. : provideOptions
  646. Reflect.ownKeys(provides).forEach(key => {
  647. provide(key, provides[key])
  648. })
  649. }
  650. if (created) {
  651. callHook(created, instance, LifecycleHooks.CREATED)
  652. }
  653. function registerLifecycleHook(
  654. register: Function,
  655. hook?: Function | Function[],
  656. ) {
  657. if (isArray(hook)) {
  658. hook.forEach(_hook => register(_hook.bind(publicThis)))
  659. } else if (hook) {
  660. register(hook.bind(publicThis))
  661. }
  662. }
  663. registerLifecycleHook(onBeforeMount, beforeMount)
  664. registerLifecycleHook(onMounted, mounted)
  665. registerLifecycleHook(onBeforeUpdate, beforeUpdate)
  666. registerLifecycleHook(onUpdated, updated)
  667. registerLifecycleHook(onActivated, activated)
  668. registerLifecycleHook(onDeactivated, deactivated)
  669. registerLifecycleHook(onErrorCaptured, errorCaptured)
  670. registerLifecycleHook(onRenderTracked, renderTracked)
  671. registerLifecycleHook(onRenderTriggered, renderTriggered)
  672. registerLifecycleHook(onBeforeUnmount, beforeUnmount)
  673. registerLifecycleHook(onUnmounted, unmounted)
  674. registerLifecycleHook(onServerPrefetch, serverPrefetch)
  675. if (__COMPAT__) {
  676. if (
  677. beforeDestroy &&
  678. softAssertCompatEnabled(DeprecationTypes.OPTIONS_BEFORE_DESTROY, instance)
  679. ) {
  680. registerLifecycleHook(onBeforeUnmount, beforeDestroy)
  681. }
  682. if (
  683. destroyed &&
  684. softAssertCompatEnabled(DeprecationTypes.OPTIONS_DESTROYED, instance)
  685. ) {
  686. registerLifecycleHook(onUnmounted, destroyed)
  687. }
  688. }
  689. if (isArray(expose)) {
  690. if (expose.length) {
  691. const exposed = instance.exposed || (instance.exposed = {})
  692. expose.forEach(key => {
  693. Object.defineProperty(exposed, key, {
  694. get: () => publicThis[key],
  695. set: val => (publicThis[key] = val),
  696. })
  697. })
  698. } else if (!instance.exposed) {
  699. instance.exposed = {}
  700. }
  701. }
  702. // options that are handled when creating the instance but also need to be
  703. // applied from mixins
  704. if (render && instance.render === NOOP) {
  705. instance.render = render as InternalRenderFunction
  706. }
  707. if (inheritAttrs != null) {
  708. instance.inheritAttrs = inheritAttrs
  709. }
  710. // asset options.
  711. if (components) instance.components = components as any
  712. if (directives) instance.directives = directives
  713. if (
  714. __COMPAT__ &&
  715. filters &&
  716. isCompatEnabled(DeprecationTypes.FILTERS, instance)
  717. ) {
  718. instance.filters = filters
  719. }
  720. if (__SSR__ && serverPrefetch) {
  721. markAsyncBoundary(instance)
  722. }
  723. }
  724. export function resolveInjections(
  725. injectOptions: ComponentInjectOptions,
  726. ctx: any,
  727. checkDuplicateProperties = NOOP as any,
  728. ): void {
  729. if (isArray(injectOptions)) {
  730. injectOptions = normalizeInject(injectOptions)!
  731. }
  732. for (const key in injectOptions) {
  733. const opt = injectOptions[key]
  734. let injected: unknown
  735. if (isObject(opt)) {
  736. if ('default' in opt) {
  737. injected = inject(
  738. opt.from || key,
  739. opt.default,
  740. true /* treat default function as factory */,
  741. )
  742. } else {
  743. injected = inject(opt.from || key)
  744. }
  745. } else {
  746. injected = inject(opt)
  747. }
  748. if (isRef(injected)) {
  749. // unwrap injected refs (ref #4196)
  750. Object.defineProperty(ctx, key, {
  751. enumerable: true,
  752. configurable: true,
  753. get: () => (injected as Ref).value,
  754. set: v => ((injected as Ref).value = v),
  755. })
  756. } else {
  757. ctx[key] = injected
  758. }
  759. if (__DEV__) {
  760. checkDuplicateProperties!(OptionTypes.INJECT, key)
  761. }
  762. }
  763. }
  764. function callHook(
  765. hook: Function,
  766. instance: ComponentInternalInstance,
  767. type: LifecycleHooks,
  768. ) {
  769. callWithAsyncErrorHandling(
  770. isArray(hook)
  771. ? hook.map(h => h.bind(instance.proxy!))
  772. : hook.bind(instance.proxy!),
  773. instance,
  774. type,
  775. )
  776. }
  777. export function createWatcher(
  778. raw: ComponentWatchOptionItem,
  779. ctx: Data,
  780. publicThis: ComponentPublicInstance,
  781. key: string,
  782. ): void {
  783. const getter = key.includes('.')
  784. ? createPathGetter(publicThis, key)
  785. : () => (publicThis as any)[key]
  786. if (isString(raw)) {
  787. const handler = ctx[raw]
  788. if (isFunction(handler)) {
  789. watch(getter, handler as WatchCallback)
  790. } else if (__DEV__) {
  791. warn(`Invalid watch handler specified by key "${raw}"`, handler)
  792. }
  793. } else if (isFunction(raw)) {
  794. watch(getter, raw.bind(publicThis))
  795. } else if (isObject(raw)) {
  796. if (isArray(raw)) {
  797. raw.forEach(r => createWatcher(r, ctx, publicThis, key))
  798. } else {
  799. const handler = isFunction(raw.handler)
  800. ? raw.handler.bind(publicThis)
  801. : (ctx[raw.handler] as WatchCallback)
  802. if (isFunction(handler)) {
  803. watch(getter, handler, raw)
  804. } else if (__DEV__) {
  805. warn(`Invalid watch handler specified by key "${raw.handler}"`, handler)
  806. }
  807. }
  808. } else if (__DEV__) {
  809. warn(`Invalid watch option: "${key}"`, raw)
  810. }
  811. }
  812. /**
  813. * Resolve merged options and cache it on the component.
  814. * This is done only once per-component since the merging does not involve
  815. * instances.
  816. */
  817. export function resolveMergedOptions(
  818. instance: ComponentInternalInstance,
  819. ): MergedComponentOptions {
  820. const base = instance.type as ComponentOptions
  821. const { mixins, extends: extendsOptions } = base
  822. const {
  823. mixins: globalMixins,
  824. optionsCache: cache,
  825. config: { optionMergeStrategies },
  826. } = instance.appContext
  827. const cached = cache.get(base)
  828. let resolved: MergedComponentOptions
  829. if (cached) {
  830. resolved = cached
  831. } else if (!globalMixins.length && !mixins && !extendsOptions) {
  832. if (
  833. __COMPAT__ &&
  834. isCompatEnabled(DeprecationTypes.PRIVATE_APIS, instance)
  835. ) {
  836. resolved = extend({}, base) as MergedComponentOptions
  837. resolved.parent = instance.parent && instance.parent.proxy
  838. resolved.propsData = instance.vnode.props
  839. } else {
  840. resolved = base as MergedComponentOptions
  841. }
  842. } else {
  843. resolved = {}
  844. if (globalMixins.length) {
  845. globalMixins.forEach(m =>
  846. mergeOptions(resolved, m, optionMergeStrategies, true),
  847. )
  848. }
  849. mergeOptions(resolved, base, optionMergeStrategies)
  850. }
  851. if (isObject(base)) {
  852. cache.set(base, resolved)
  853. }
  854. return resolved
  855. }
  856. export function mergeOptions(
  857. to: any,
  858. from: any,
  859. strats: Record<string, OptionMergeFunction>,
  860. asMixin = false,
  861. ): any {
  862. if (__COMPAT__ && isFunction(from)) {
  863. from = from.options
  864. }
  865. const { mixins, extends: extendsOptions } = from
  866. if (extendsOptions) {
  867. mergeOptions(to, extendsOptions, strats, true)
  868. }
  869. if (mixins) {
  870. mixins.forEach((m: ComponentOptionsMixin) =>
  871. mergeOptions(to, m, strats, true),
  872. )
  873. }
  874. for (const key in from) {
  875. if (asMixin && key === 'expose') {
  876. __DEV__ &&
  877. warn(
  878. `"expose" option is ignored when declared in mixins or extends. ` +
  879. `It should only be declared in the base component itself.`,
  880. )
  881. } else {
  882. const strat = internalOptionMergeStrats[key] || (strats && strats[key])
  883. to[key] = strat ? strat(to[key], from[key]) : from[key]
  884. }
  885. }
  886. return to
  887. }
  888. export const internalOptionMergeStrats: Record<string, Function> = {
  889. data: mergeDataFn,
  890. props: mergeEmitsOrPropsOptions,
  891. emits: mergeEmitsOrPropsOptions,
  892. // objects
  893. methods: mergeObjectOptions,
  894. computed: mergeObjectOptions,
  895. // lifecycle
  896. beforeCreate: mergeAsArray,
  897. created: mergeAsArray,
  898. beforeMount: mergeAsArray,
  899. mounted: mergeAsArray,
  900. beforeUpdate: mergeAsArray,
  901. updated: mergeAsArray,
  902. beforeDestroy: mergeAsArray,
  903. beforeUnmount: mergeAsArray,
  904. destroyed: mergeAsArray,
  905. unmounted: mergeAsArray,
  906. activated: mergeAsArray,
  907. deactivated: mergeAsArray,
  908. errorCaptured: mergeAsArray,
  909. serverPrefetch: mergeAsArray,
  910. // assets
  911. components: mergeObjectOptions,
  912. directives: mergeObjectOptions,
  913. // watch
  914. watch: mergeWatchOptions,
  915. // provide / inject
  916. provide: mergeDataFn,
  917. inject: mergeInject,
  918. }
  919. if (__COMPAT__) {
  920. internalOptionMergeStrats.filters = mergeObjectOptions
  921. }
  922. function mergeDataFn(to: any, from: any) {
  923. if (!from) {
  924. return to
  925. }
  926. if (!to) {
  927. return from
  928. }
  929. return function mergedDataFn(this: ComponentPublicInstance) {
  930. return (
  931. __COMPAT__ && isCompatEnabled(DeprecationTypes.OPTIONS_DATA_MERGE, null)
  932. ? deepMergeData
  933. : extend
  934. )(
  935. isFunction(to) ? to.call(this, this) : to,
  936. isFunction(from) ? from.call(this, this) : from,
  937. )
  938. }
  939. }
  940. function mergeInject(
  941. to: ComponentInjectOptions | undefined,
  942. from: ComponentInjectOptions,
  943. ) {
  944. return mergeObjectOptions(normalizeInject(to), normalizeInject(from))
  945. }
  946. function normalizeInject(
  947. raw: ComponentInjectOptions | undefined,
  948. ): ObjectInjectOptions | undefined {
  949. if (isArray(raw)) {
  950. const res: ObjectInjectOptions = {}
  951. for (let i = 0; i < raw.length; i++) {
  952. res[raw[i]] = raw[i]
  953. }
  954. return res
  955. }
  956. return raw
  957. }
  958. function mergeAsArray<T = Function>(to: T[] | T | undefined, from: T | T[]) {
  959. return to ? [...new Set([].concat(to as any, from as any))] : from
  960. }
  961. function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
  962. return to ? extend(Object.create(null), to, from) : from
  963. }
  964. function mergeEmitsOrPropsOptions(
  965. to: EmitsOptions | undefined,
  966. from: EmitsOptions | undefined,
  967. ): EmitsOptions | undefined
  968. function mergeEmitsOrPropsOptions(
  969. to: ComponentPropsOptions | undefined,
  970. from: ComponentPropsOptions | undefined,
  971. ): ComponentPropsOptions | undefined
  972. function mergeEmitsOrPropsOptions(
  973. to: ComponentPropsOptions | EmitsOptions | undefined,
  974. from: ComponentPropsOptions | EmitsOptions | undefined,
  975. ) {
  976. if (to) {
  977. if (isArray(to) && isArray(from)) {
  978. return [...new Set([...to, ...from])]
  979. }
  980. return extend(
  981. Object.create(null),
  982. normalizePropsOrEmits(to),
  983. normalizePropsOrEmits(from ?? {}),
  984. )
  985. } else {
  986. return from
  987. }
  988. }
  989. function mergeWatchOptions(
  990. to: ComponentWatchOptions | undefined,
  991. from: ComponentWatchOptions | undefined,
  992. ) {
  993. if (!to) return from
  994. if (!from) return to
  995. const merged = extend(Object.create(null), to)
  996. for (const key in from) {
  997. merged[key] = mergeAsArray(to[key], from[key])
  998. }
  999. return merged
  1000. }
  1001. // Deprecated legacy types, kept because they were previously exported ---------
  1002. /**
  1003. * @deprecated
  1004. */
  1005. export type ComponentOptionsWithoutProps<
  1006. Props = {},
  1007. RawBindings = {},
  1008. D = {},
  1009. C extends ComputedOptions = {},
  1010. M extends MethodOptions = {},
  1011. Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  1012. Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  1013. E extends EmitsOptions = {},
  1014. EE extends string = string,
  1015. I extends ComponentInjectOptions = {},
  1016. II extends string = string,
  1017. S extends SlotsType = {},
  1018. LC extends Record<string, Component> = {},
  1019. Directives extends Record<string, Directive> = {},
  1020. Exposed extends string = string,
  1021. Provide extends ComponentProvideOptions = ComponentProvideOptions,
  1022. TE extends ComponentTypeEmits = {},
  1023. ResolvedEmits extends EmitsOptions = {} extends E
  1024. ? TypeEmitsToOptions<TE>
  1025. : E,
  1026. PE = Props & EmitsToProps<ResolvedEmits>,
  1027. > = ComponentOptionsBase<
  1028. PE,
  1029. RawBindings,
  1030. D,
  1031. C,
  1032. M,
  1033. Mixin,
  1034. Extends,
  1035. E,
  1036. EE,
  1037. {},
  1038. I,
  1039. II,
  1040. S,
  1041. LC,
  1042. Directives,
  1043. Exposed,
  1044. Provide
  1045. > & {
  1046. props?: never
  1047. /**
  1048. * @private for language-tools use only
  1049. */
  1050. __typeProps?: Props
  1051. /**
  1052. * @private for language-tools use only
  1053. */
  1054. __typeEmits?: TE
  1055. } & ThisType<
  1056. CreateComponentPublicInstanceWithMixins<
  1057. PE,
  1058. RawBindings,
  1059. D,
  1060. C,
  1061. M,
  1062. Mixin,
  1063. Extends,
  1064. ResolvedEmits,
  1065. EE,
  1066. {},
  1067. false,
  1068. I,
  1069. S,
  1070. LC,
  1071. Directives,
  1072. Exposed
  1073. >
  1074. >
  1075. /**
  1076. * @deprecated
  1077. */
  1078. export type ComponentOptionsWithArrayProps<
  1079. PropNames extends string = string,
  1080. RawBindings = {},
  1081. D = {},
  1082. C extends ComputedOptions = {},
  1083. M extends MethodOptions = {},
  1084. Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  1085. Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  1086. E extends EmitsOptions = EmitsOptions,
  1087. EE extends string = string,
  1088. I extends ComponentInjectOptions = {},
  1089. II extends string = string,
  1090. S extends SlotsType = {},
  1091. LC extends Record<string, Component> = {},
  1092. Directives extends Record<string, Directive> = {},
  1093. Exposed extends string = string,
  1094. Provide extends ComponentProvideOptions = ComponentProvideOptions,
  1095. Props = Prettify<Readonly<{ [key in PropNames]?: any } & EmitsToProps<E>>>,
  1096. > = ComponentOptionsBase<
  1097. Props,
  1098. RawBindings,
  1099. D,
  1100. C,
  1101. M,
  1102. Mixin,
  1103. Extends,
  1104. E,
  1105. EE,
  1106. {},
  1107. I,
  1108. II,
  1109. S,
  1110. LC,
  1111. Directives,
  1112. Exposed,
  1113. Provide
  1114. > & {
  1115. props: PropNames[]
  1116. } & ThisType<
  1117. CreateComponentPublicInstanceWithMixins<
  1118. Props,
  1119. RawBindings,
  1120. D,
  1121. C,
  1122. M,
  1123. Mixin,
  1124. Extends,
  1125. E,
  1126. Props,
  1127. {},
  1128. false,
  1129. I,
  1130. S,
  1131. LC,
  1132. Directives,
  1133. Exposed
  1134. >
  1135. >
  1136. /**
  1137. * @deprecated
  1138. */
  1139. export type ComponentOptionsWithObjectProps<
  1140. PropsOptions = ComponentObjectPropsOptions,
  1141. RawBindings = {},
  1142. D = {},
  1143. C extends ComputedOptions = {},
  1144. M extends MethodOptions = {},
  1145. Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  1146. Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  1147. E extends EmitsOptions = EmitsOptions,
  1148. EE extends string = string,
  1149. I extends ComponentInjectOptions = {},
  1150. II extends string = string,
  1151. S extends SlotsType = {},
  1152. LC extends Record<string, Component> = {},
  1153. Directives extends Record<string, Directive> = {},
  1154. Exposed extends string = string,
  1155. Provide extends ComponentProvideOptions = ComponentProvideOptions,
  1156. Props = Prettify<Readonly<ExtractPropTypes<PropsOptions> & EmitsToProps<E>>>,
  1157. Defaults = ExtractDefaultPropTypes<PropsOptions>,
  1158. > = ComponentOptionsBase<
  1159. Props,
  1160. RawBindings,
  1161. D,
  1162. C,
  1163. M,
  1164. Mixin,
  1165. Extends,
  1166. E,
  1167. EE,
  1168. Defaults,
  1169. I,
  1170. II,
  1171. S,
  1172. LC,
  1173. Directives,
  1174. Exposed,
  1175. Provide
  1176. > & {
  1177. props: PropsOptions & ThisType<void>
  1178. } & ThisType<
  1179. CreateComponentPublicInstanceWithMixins<
  1180. Props,
  1181. RawBindings,
  1182. D,
  1183. C,
  1184. M,
  1185. Mixin,
  1186. Extends,
  1187. E,
  1188. Props,
  1189. Defaults,
  1190. false,
  1191. I,
  1192. S,
  1193. LC,
  1194. Directives
  1195. >
  1196. >