componentOptions.ts 32 KB

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