componentOptions.ts 31 KB

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