componentOptions.ts 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039
  1. import {
  2. ComponentInternalInstance,
  3. Data,
  4. SetupContext,
  5. ComponentInternalOptions,
  6. Component,
  7. ConcreteComponent,
  8. InternalRenderFunction,
  9. LifecycleHooks
  10. } from './component'
  11. import {
  12. isFunction,
  13. extend,
  14. isString,
  15. isObject,
  16. isArray,
  17. EMPTY_OBJ,
  18. NOOP,
  19. hasOwn,
  20. isPromise
  21. } from '@vue/shared'
  22. import { computed } from './apiComputed'
  23. import {
  24. watch,
  25. WatchOptions,
  26. WatchCallback,
  27. createPathGetter
  28. } from './apiWatch'
  29. import { provide, inject } from './apiInject'
  30. import {
  31. onBeforeMount,
  32. onMounted,
  33. onBeforeUpdate,
  34. onUpdated,
  35. onErrorCaptured,
  36. onRenderTracked,
  37. onBeforeUnmount,
  38. onUnmounted,
  39. onActivated,
  40. onDeactivated,
  41. onRenderTriggered,
  42. DebuggerHook,
  43. ErrorCapturedHook
  44. } from './apiLifecycle'
  45. import {
  46. reactive,
  47. ComputedGetter,
  48. WritableComputedOptions,
  49. toRaw,
  50. proxyRefs,
  51. toRef
  52. } from '@vue/reactivity'
  53. import {
  54. ComponentObjectPropsOptions,
  55. ExtractPropTypes,
  56. ExtractDefaultPropTypes
  57. } from './componentProps'
  58. import { EmitsOptions } from './componentEmits'
  59. import { Directive } from './directives'
  60. import {
  61. CreateComponentPublicInstance,
  62. ComponentPublicInstance
  63. } from './componentPublicInstance'
  64. import { warn } from './warning'
  65. import { VNodeChild } from './vnode'
  66. import { callWithAsyncErrorHandling } from './errorHandling'
  67. import { UnionToIntersection } from './helpers/typeUtils'
  68. import { deepMergeData } from './compat/data'
  69. import { DeprecationTypes } from './compat/compatConfig'
  70. import {
  71. CompatConfig,
  72. isCompatEnabled,
  73. softAssertCompatEnabled
  74. } from './compat/compatConfig'
  75. import {
  76. AssetTypes,
  77. COMPONENTS,
  78. DIRECTIVES,
  79. FILTERS
  80. } from './helpers/resolveAssets'
  81. /**
  82. * Interface for declaring custom options.
  83. *
  84. * @example
  85. * ```ts
  86. * declare module '@vue/runtime-core' {
  87. * interface ComponentCustomOptions {
  88. * beforeRouteUpdate?(
  89. * to: Route,
  90. * from: Route,
  91. * next: () => void
  92. * ): void
  93. * }
  94. * }
  95. * ```
  96. */
  97. export interface ComponentCustomOptions {}
  98. export type RenderFunction = () => VNodeChild
  99. type ExtractOptionProp<T> = T extends ComponentOptionsBase<
  100. infer P,
  101. any,
  102. any,
  103. any,
  104. any,
  105. any,
  106. any,
  107. any
  108. >
  109. ? unknown extends P ? {} : P
  110. : {}
  111. export interface ComponentOptionsBase<
  112. Props,
  113. RawBindings,
  114. D,
  115. C extends ComputedOptions,
  116. M extends MethodOptions,
  117. Mixin extends ComponentOptionsMixin,
  118. Extends extends ComponentOptionsMixin,
  119. E extends EmitsOptions,
  120. EE extends string = string,
  121. Defaults = {}
  122. >
  123. extends LegacyOptions<Props, D, C, M, Mixin, Extends>,
  124. ComponentInternalOptions,
  125. ComponentCustomOptions {
  126. setup?: (
  127. this: void,
  128. props: Props &
  129. UnionToIntersection<ExtractOptionProp<Mixin>> &
  130. UnionToIntersection<ExtractOptionProp<Extends>>,
  131. ctx: SetupContext<E>
  132. ) => Promise<RawBindings> | RawBindings | RenderFunction | void
  133. name?: string
  134. template?: string | object // can be a direct DOM node
  135. // Note: we are intentionally using the signature-less `Function` type here
  136. // since any type with signature will cause the whole inference to fail when
  137. // the return expression contains reference to `this`.
  138. // Luckily `render()` doesn't need any arguments nor does it care about return
  139. // type.
  140. render?: Function
  141. components?: Record<string, Component>
  142. directives?: Record<string, Directive>
  143. inheritAttrs?: boolean
  144. emits?: (E | EE[]) & ThisType<void>
  145. // TODO infer public instance type based on exposed keys
  146. expose?: string[]
  147. serverPrefetch?(): Promise<any>
  148. // Internal ------------------------------------------------------------------
  149. /**
  150. * SSR only. This is produced by compiler-ssr and attached in compiler-sfc
  151. * not user facing, so the typing is lax and for test only.
  152. * @internal
  153. */
  154. ssrRender?: (
  155. ctx: any,
  156. push: (item: any) => void,
  157. parentInstance: ComponentInternalInstance,
  158. attrs: Data | undefined,
  159. // for compiler-optimized bindings
  160. $props: ComponentInternalInstance['props'],
  161. $setup: ComponentInternalInstance['setupState'],
  162. $data: ComponentInternalInstance['data'],
  163. $options: ComponentInternalInstance['ctx']
  164. ) => void
  165. /**
  166. * Only generated by compiler-sfc to mark a ssr render function inlined and
  167. * returned from setup()
  168. * @internal
  169. */
  170. __ssrInlineRender?: boolean
  171. /**
  172. * marker for AsyncComponentWrapper
  173. * @internal
  174. */
  175. __asyncLoader?: () => Promise<ConcreteComponent>
  176. /**
  177. * cache for merged $options
  178. * @internal
  179. */
  180. __merged?: ComponentOptions
  181. // Type differentiators ------------------------------------------------------
  182. // Note these are internal but need to be exposed in d.ts for type inference
  183. // to work!
  184. // type-only differentiator to separate OptionWithoutProps from a constructor
  185. // type returned by defineComponent() or FunctionalComponent
  186. call?: (this: unknown, ...args: unknown[]) => never
  187. // type-only differentiators for built-in Vnode types
  188. __isFragment?: never
  189. __isTeleport?: never
  190. __isSuspense?: never
  191. __defaults?: Defaults
  192. }
  193. export type ComponentOptionsWithoutProps<
  194. Props = {},
  195. RawBindings = {},
  196. D = {},
  197. C extends ComputedOptions = {},
  198. M extends MethodOptions = {},
  199. Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  200. Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  201. E extends EmitsOptions = EmitsOptions,
  202. EE extends string = string
  203. > = ComponentOptionsBase<
  204. Props,
  205. RawBindings,
  206. D,
  207. C,
  208. M,
  209. Mixin,
  210. Extends,
  211. E,
  212. EE,
  213. {}
  214. > & {
  215. props?: undefined
  216. } & ThisType<
  217. CreateComponentPublicInstance<{}, RawBindings, D, C, M, Mixin, Extends, E>
  218. >
  219. export type ComponentOptionsWithArrayProps<
  220. PropNames extends string = string,
  221. RawBindings = {},
  222. D = {},
  223. C extends ComputedOptions = {},
  224. M extends MethodOptions = {},
  225. Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  226. Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  227. E extends EmitsOptions = EmitsOptions,
  228. EE extends string = string,
  229. Props = Readonly<{ [key in PropNames]?: any }>
  230. > = ComponentOptionsBase<
  231. Props,
  232. RawBindings,
  233. D,
  234. C,
  235. M,
  236. Mixin,
  237. Extends,
  238. E,
  239. EE,
  240. {}
  241. > & {
  242. props: PropNames[]
  243. } & ThisType<
  244. CreateComponentPublicInstance<
  245. Props,
  246. RawBindings,
  247. D,
  248. C,
  249. M,
  250. Mixin,
  251. Extends,
  252. E
  253. >
  254. >
  255. export type ComponentOptionsWithObjectProps<
  256. PropsOptions = ComponentObjectPropsOptions,
  257. RawBindings = {},
  258. D = {},
  259. C extends ComputedOptions = {},
  260. M extends MethodOptions = {},
  261. Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
  262. Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
  263. E extends EmitsOptions = EmitsOptions,
  264. EE extends string = string,
  265. Props = Readonly<ExtractPropTypes<PropsOptions>>,
  266. Defaults = ExtractDefaultPropTypes<PropsOptions>
  267. > = ComponentOptionsBase<
  268. Props,
  269. RawBindings,
  270. D,
  271. C,
  272. M,
  273. Mixin,
  274. Extends,
  275. E,
  276. EE,
  277. Defaults
  278. > & {
  279. props: PropsOptions & ThisType<void>
  280. } & ThisType<
  281. CreateComponentPublicInstance<
  282. Props,
  283. RawBindings,
  284. D,
  285. C,
  286. M,
  287. Mixin,
  288. Extends,
  289. E,
  290. Props,
  291. Defaults,
  292. false
  293. >
  294. >
  295. export type ComponentOptions<
  296. Props = {},
  297. RawBindings = any,
  298. D = any,
  299. C extends ComputedOptions = any,
  300. M extends MethodOptions = any,
  301. Mixin extends ComponentOptionsMixin = any,
  302. Extends extends ComponentOptionsMixin = any,
  303. E extends EmitsOptions = any
  304. > = ComponentOptionsBase<Props, RawBindings, D, C, M, Mixin, Extends, E> &
  305. ThisType<
  306. CreateComponentPublicInstance<
  307. {},
  308. RawBindings,
  309. D,
  310. C,
  311. M,
  312. Mixin,
  313. Extends,
  314. E,
  315. Readonly<Props>
  316. >
  317. >
  318. export type ComponentOptionsMixin = ComponentOptionsBase<
  319. any,
  320. any,
  321. any,
  322. any,
  323. any,
  324. any,
  325. any,
  326. any,
  327. any,
  328. any
  329. >
  330. export type ComputedOptions = Record<
  331. string,
  332. ComputedGetter<any> | WritableComputedOptions<any>
  333. >
  334. export interface MethodOptions {
  335. [key: string]: Function
  336. }
  337. export type ExtractComputedReturns<T extends any> = {
  338. [key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }
  339. ? TReturn
  340. : T[key] extends (...args: any[]) => infer TReturn ? TReturn : never
  341. }
  342. export type ObjectWatchOptionItem = {
  343. handler: WatchCallback | string
  344. } & WatchOptions
  345. type WatchOptionItem = string | WatchCallback | ObjectWatchOptionItem
  346. type ComponentWatchOptionItem = WatchOptionItem | WatchOptionItem[]
  347. type ComponentWatchOptions = Record<string, ComponentWatchOptionItem>
  348. type ComponentInjectOptions =
  349. | string[]
  350. | Record<
  351. string | symbol,
  352. string | symbol | { from?: string | symbol; default?: unknown }
  353. >
  354. interface LegacyOptions<
  355. Props,
  356. D,
  357. C extends ComputedOptions,
  358. M extends MethodOptions,
  359. Mixin extends ComponentOptionsMixin,
  360. Extends extends ComponentOptionsMixin
  361. > {
  362. compatConfig?: CompatConfig
  363. // allow any custom options
  364. [key: string]: any
  365. // state
  366. // Limitation: we cannot expose RawBindings on the `this` context for data
  367. // since that leads to some sort of circular inference and breaks ThisType
  368. // for the entire component.
  369. data?: (
  370. this: CreateComponentPublicInstance<
  371. Props,
  372. {},
  373. {},
  374. {},
  375. MethodOptions,
  376. Mixin,
  377. Extends
  378. >,
  379. vm: CreateComponentPublicInstance<
  380. Props,
  381. {},
  382. {},
  383. {},
  384. MethodOptions,
  385. Mixin,
  386. Extends
  387. >
  388. ) => D
  389. computed?: C
  390. methods?: M
  391. watch?: ComponentWatchOptions
  392. provide?: Data | Function
  393. inject?: ComponentInjectOptions
  394. // assets
  395. filters?: Record<string, Function>
  396. // composition
  397. mixins?: Mixin[]
  398. extends?: Extends
  399. // lifecycle
  400. beforeCreate?(): void
  401. created?(): void
  402. beforeMount?(): void
  403. mounted?(): void
  404. beforeUpdate?(): void
  405. updated?(): void
  406. activated?(): void
  407. deactivated?(): void
  408. /** @deprecated use `beforeUnmount` instead */
  409. beforeDestroy?(): void
  410. beforeUnmount?(): void
  411. /** @deprecated use `unmounted` instead */
  412. destroyed?(): void
  413. unmounted?(): void
  414. renderTracked?: DebuggerHook
  415. renderTriggered?: DebuggerHook
  416. errorCaptured?: ErrorCapturedHook
  417. // runtime compile only
  418. delimiters?: [string, string]
  419. /**
  420. * #3468
  421. *
  422. * type-only, used to assist Mixin's type inference,
  423. * typescript will try to simplify the inferred `Mixin` type,
  424. * with the `__differenciator`, typescript won't be able to combine different mixins,
  425. * because the `__differenciator` will be different
  426. */
  427. __differentiator?: keyof D | keyof C | keyof M
  428. }
  429. export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'Defaults'
  430. export type OptionTypesType<
  431. P = {},
  432. B = {},
  433. D = {},
  434. C extends ComputedOptions = {},
  435. M extends MethodOptions = {},
  436. Defaults = {}
  437. > = {
  438. P: P
  439. B: B
  440. D: D
  441. C: C
  442. M: M
  443. Defaults: Defaults
  444. }
  445. const enum OptionTypes {
  446. PROPS = 'Props',
  447. DATA = 'Data',
  448. COMPUTED = 'Computed',
  449. METHODS = 'Methods',
  450. INJECT = 'Inject'
  451. }
  452. function createDuplicateChecker() {
  453. const cache = Object.create(null)
  454. return (type: OptionTypes, key: string) => {
  455. if (cache[key]) {
  456. warn(`${type} property "${key}" is already defined in ${cache[key]}.`)
  457. } else {
  458. cache[key] = type
  459. }
  460. }
  461. }
  462. type DataFn = (vm: ComponentPublicInstance) => any
  463. export let shouldCacheAccess = true
  464. export function applyOptions(
  465. instance: ComponentInternalInstance,
  466. options: ComponentOptions,
  467. deferredData: DataFn[] = [],
  468. deferredWatch: ComponentWatchOptions[] = [],
  469. deferredProvide: (Data | Function)[] = [],
  470. asMixin: boolean = false
  471. ) {
  472. if (__COMPAT__ && isFunction(options)) {
  473. options = options.options
  474. }
  475. const {
  476. // composition
  477. mixins,
  478. extends: extendsOptions,
  479. // state
  480. data: dataOptions,
  481. computed: computedOptions,
  482. methods,
  483. watch: watchOptions,
  484. provide: provideOptions,
  485. inject: injectOptions,
  486. // lifecycle
  487. beforeMount,
  488. mounted,
  489. beforeUpdate,
  490. updated,
  491. activated,
  492. deactivated,
  493. beforeDestroy,
  494. beforeUnmount,
  495. destroyed,
  496. unmounted,
  497. render,
  498. renderTracked,
  499. renderTriggered,
  500. errorCaptured,
  501. // public API
  502. expose
  503. } = options
  504. const publicThis = instance.proxy!
  505. const ctx = instance.ctx
  506. const globalMixins = instance.appContext.mixins
  507. if (asMixin && render && instance.render === NOOP) {
  508. instance.render = render as InternalRenderFunction
  509. }
  510. // applyOptions is called non-as-mixin once per instance
  511. if (!asMixin) {
  512. shouldCacheAccess = false
  513. callSyncHook(
  514. 'beforeCreate',
  515. LifecycleHooks.BEFORE_CREATE,
  516. options,
  517. instance,
  518. globalMixins
  519. )
  520. shouldCacheAccess = true
  521. // global mixins are applied first
  522. applyMixins(
  523. instance,
  524. globalMixins,
  525. deferredData,
  526. deferredWatch,
  527. deferredProvide
  528. )
  529. }
  530. // extending a base component...
  531. if (extendsOptions) {
  532. applyOptions(
  533. instance,
  534. extendsOptions,
  535. deferredData,
  536. deferredWatch,
  537. deferredProvide,
  538. true
  539. )
  540. }
  541. // local mixins
  542. if (mixins) {
  543. applyMixins(instance, mixins, deferredData, deferredWatch, deferredProvide)
  544. }
  545. const checkDuplicateProperties = __DEV__ ? createDuplicateChecker() : null
  546. if (__DEV__) {
  547. const [propsOptions] = instance.propsOptions
  548. if (propsOptions) {
  549. for (const key in propsOptions) {
  550. checkDuplicateProperties!(OptionTypes.PROPS, key)
  551. }
  552. }
  553. }
  554. // options initialization order (to be consistent with Vue 2):
  555. // - props (already done outside of this function)
  556. // - inject
  557. // - methods
  558. // - data (deferred since it relies on `this` access)
  559. // - computed
  560. // - watch (deferred since it relies on `this` access)
  561. if (injectOptions) {
  562. resolveInjections(injectOptions, ctx, checkDuplicateProperties)
  563. }
  564. if (methods) {
  565. for (const key in methods) {
  566. const methodHandler = (methods as MethodOptions)[key]
  567. if (isFunction(methodHandler)) {
  568. // In dev mode, we use the `createRenderContext` function to define methods to the proxy target,
  569. // and those are read-only but reconfigurable, so it needs to be redefined here
  570. if (__DEV__) {
  571. Object.defineProperty(ctx, key, {
  572. value: methodHandler.bind(publicThis),
  573. configurable: true,
  574. enumerable: true,
  575. writable: true
  576. })
  577. } else {
  578. ctx[key] = methodHandler.bind(publicThis)
  579. }
  580. if (__DEV__) {
  581. checkDuplicateProperties!(OptionTypes.METHODS, key)
  582. }
  583. } else if (__DEV__) {
  584. warn(
  585. `Method "${key}" has type "${typeof methodHandler}" in the component definition. ` +
  586. `Did you reference the function correctly?`
  587. )
  588. }
  589. }
  590. }
  591. if (!asMixin) {
  592. if (deferredData.length) {
  593. deferredData.forEach(dataFn => resolveData(instance, dataFn, publicThis))
  594. }
  595. if (dataOptions) {
  596. // @ts-ignore dataOptions is not fully type safe
  597. resolveData(instance, dataOptions, publicThis)
  598. }
  599. if (__DEV__) {
  600. const rawData = toRaw(instance.data)
  601. for (const key in rawData) {
  602. checkDuplicateProperties!(OptionTypes.DATA, key)
  603. // expose data on ctx during dev
  604. if (key[0] !== '$' && key[0] !== '_') {
  605. Object.defineProperty(ctx, key, {
  606. configurable: true,
  607. enumerable: true,
  608. get: () => rawData[key],
  609. set: NOOP
  610. })
  611. }
  612. }
  613. }
  614. } else if (dataOptions) {
  615. deferredData.push(dataOptions as DataFn)
  616. }
  617. if (computedOptions) {
  618. for (const key in computedOptions) {
  619. const opt = (computedOptions as ComputedOptions)[key]
  620. const get = isFunction(opt)
  621. ? opt.bind(publicThis, publicThis)
  622. : isFunction(opt.get)
  623. ? opt.get.bind(publicThis, publicThis)
  624. : NOOP
  625. if (__DEV__ && get === NOOP) {
  626. warn(`Computed property "${key}" has no getter.`)
  627. }
  628. const set =
  629. !isFunction(opt) && isFunction(opt.set)
  630. ? opt.set.bind(publicThis)
  631. : __DEV__
  632. ? () => {
  633. warn(
  634. `Write operation failed: computed property "${key}" is readonly.`
  635. )
  636. }
  637. : NOOP
  638. const c = computed({
  639. get,
  640. set
  641. })
  642. Object.defineProperty(ctx, key, {
  643. enumerable: true,
  644. configurable: true,
  645. get: () => c.value,
  646. set: v => (c.value = v)
  647. })
  648. if (__DEV__) {
  649. checkDuplicateProperties!(OptionTypes.COMPUTED, key)
  650. }
  651. }
  652. }
  653. if (watchOptions) {
  654. deferredWatch.push(watchOptions)
  655. }
  656. if (!asMixin && deferredWatch.length) {
  657. deferredWatch.forEach(watchOptions => {
  658. for (const key in watchOptions) {
  659. createWatcher(watchOptions[key], ctx, publicThis, key)
  660. }
  661. })
  662. }
  663. if (provideOptions) {
  664. deferredProvide.push(provideOptions)
  665. }
  666. if (!asMixin && deferredProvide.length) {
  667. deferredProvide.forEach(provideOptions => {
  668. const provides = isFunction(provideOptions)
  669. ? provideOptions.call(publicThis)
  670. : provideOptions
  671. Reflect.ownKeys(provides).forEach(key => {
  672. provide(key, provides[key])
  673. })
  674. })
  675. }
  676. // asset options.
  677. // To reduce memory usage, only components with mixins or extends will have
  678. // resolved asset registry attached to instance.
  679. if (asMixin) {
  680. resolveInstanceAssets(instance, options, COMPONENTS)
  681. resolveInstanceAssets(instance, options, DIRECTIVES)
  682. if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) {
  683. resolveInstanceAssets(instance, options, FILTERS)
  684. }
  685. }
  686. // lifecycle options
  687. if (!asMixin) {
  688. callSyncHook(
  689. 'created',
  690. LifecycleHooks.CREATED,
  691. options,
  692. instance,
  693. globalMixins
  694. )
  695. }
  696. if (beforeMount) {
  697. onBeforeMount(beforeMount.bind(publicThis))
  698. }
  699. if (mounted) {
  700. onMounted(mounted.bind(publicThis))
  701. }
  702. if (beforeUpdate) {
  703. onBeforeUpdate(beforeUpdate.bind(publicThis))
  704. }
  705. if (updated) {
  706. onUpdated(updated.bind(publicThis))
  707. }
  708. if (activated) {
  709. onActivated(activated.bind(publicThis))
  710. }
  711. if (deactivated) {
  712. onDeactivated(deactivated.bind(publicThis))
  713. }
  714. if (errorCaptured) {
  715. onErrorCaptured(errorCaptured.bind(publicThis))
  716. }
  717. if (renderTracked) {
  718. onRenderTracked(renderTracked.bind(publicThis))
  719. }
  720. if (renderTriggered) {
  721. onRenderTriggered(renderTriggered.bind(publicThis))
  722. }
  723. if (beforeUnmount) {
  724. onBeforeUnmount(beforeUnmount.bind(publicThis))
  725. }
  726. if (unmounted) {
  727. onUnmounted(unmounted.bind(publicThis))
  728. }
  729. if (__COMPAT__) {
  730. if (
  731. beforeDestroy &&
  732. softAssertCompatEnabled(DeprecationTypes.OPTIONS_BEFORE_DESTROY, instance)
  733. ) {
  734. onBeforeUnmount(beforeDestroy.bind(publicThis))
  735. }
  736. if (
  737. destroyed &&
  738. softAssertCompatEnabled(DeprecationTypes.OPTIONS_DESTROYED, instance)
  739. ) {
  740. onUnmounted(destroyed.bind(publicThis))
  741. }
  742. }
  743. if (isArray(expose)) {
  744. if (!asMixin) {
  745. if (expose.length) {
  746. const exposed = instance.exposed || (instance.exposed = proxyRefs({}))
  747. expose.forEach(key => {
  748. exposed[key] = toRef(publicThis, key as any)
  749. })
  750. } else if (!instance.exposed) {
  751. instance.exposed = EMPTY_OBJ
  752. }
  753. } else if (__DEV__) {
  754. warn(`The \`expose\` option is ignored when used in mixins.`)
  755. }
  756. }
  757. }
  758. function resolveInstanceAssets(
  759. instance: ComponentInternalInstance,
  760. mixin: ComponentOptions,
  761. type: AssetTypes
  762. ) {
  763. if (mixin[type]) {
  764. extend(
  765. instance[type] ||
  766. (instance[type] = extend(
  767. {},
  768. (instance.type as ComponentOptions)[type]
  769. ) as any),
  770. mixin[type]
  771. )
  772. }
  773. }
  774. export function resolveInjections(
  775. injectOptions: ComponentInjectOptions,
  776. ctx: any,
  777. checkDuplicateProperties = NOOP as any
  778. ) {
  779. if (isArray(injectOptions)) {
  780. for (let i = 0; i < injectOptions.length; i++) {
  781. const key = injectOptions[i]
  782. ctx[key] = inject(key)
  783. if (__DEV__) {
  784. checkDuplicateProperties!(OptionTypes.INJECT, key)
  785. }
  786. }
  787. } else {
  788. for (const key in injectOptions) {
  789. const opt = injectOptions[key]
  790. if (isObject(opt)) {
  791. ctx[key] = inject(
  792. opt.from || key,
  793. opt.default,
  794. true /* treat default function as factory */
  795. )
  796. } else {
  797. ctx[key] = inject(opt)
  798. }
  799. if (__DEV__) {
  800. checkDuplicateProperties!(OptionTypes.INJECT, key)
  801. }
  802. }
  803. }
  804. }
  805. function callSyncHook(
  806. name: 'beforeCreate' | 'created',
  807. type: LifecycleHooks,
  808. options: ComponentOptions,
  809. instance: ComponentInternalInstance,
  810. globalMixins: ComponentOptions[]
  811. ) {
  812. for (let i = 0; i < globalMixins.length; i++) {
  813. callHookWithMixinAndExtends(name, type, globalMixins[i], instance)
  814. }
  815. callHookWithMixinAndExtends(name, type, options, instance)
  816. }
  817. function callHookWithMixinAndExtends(
  818. name: 'beforeCreate' | 'created',
  819. type: LifecycleHooks,
  820. options: ComponentOptions,
  821. instance: ComponentInternalInstance
  822. ) {
  823. const { extends: base, mixins } = options
  824. const selfHook = options[name]
  825. if (base) {
  826. callHookWithMixinAndExtends(name, type, base, instance)
  827. }
  828. if (mixins) {
  829. for (let i = 0; i < mixins.length; i++) {
  830. callHookWithMixinAndExtends(name, type, mixins[i], instance)
  831. }
  832. }
  833. if (selfHook) {
  834. callWithAsyncErrorHandling(
  835. __COMPAT__ && isArray(selfHook)
  836. ? selfHook.map(h => h.bind(instance.proxy!))
  837. : selfHook.bind(instance.proxy!),
  838. instance,
  839. type
  840. )
  841. }
  842. }
  843. function applyMixins(
  844. instance: ComponentInternalInstance,
  845. mixins: ComponentOptions[],
  846. deferredData: DataFn[],
  847. deferredWatch: ComponentWatchOptions[],
  848. deferredProvide: (Data | Function)[]
  849. ) {
  850. for (let i = 0; i < mixins.length; i++) {
  851. applyOptions(
  852. instance,
  853. mixins[i],
  854. deferredData,
  855. deferredWatch,
  856. deferredProvide,
  857. true
  858. )
  859. }
  860. }
  861. function resolveData(
  862. instance: ComponentInternalInstance,
  863. dataFn: DataFn,
  864. publicThis: ComponentPublicInstance
  865. ) {
  866. if (__DEV__ && !isFunction(dataFn)) {
  867. warn(
  868. `The data option must be a function. ` +
  869. `Plain object usage is no longer supported.`
  870. )
  871. }
  872. shouldCacheAccess = false
  873. const data = dataFn.call(publicThis, publicThis)
  874. shouldCacheAccess = true
  875. if (__DEV__ && isPromise(data)) {
  876. warn(
  877. `data() returned a Promise - note data() cannot be async; If you ` +
  878. `intend to perform data fetching before component renders, use ` +
  879. `async setup() + <Suspense>.`
  880. )
  881. }
  882. if (!isObject(data)) {
  883. __DEV__ && warn(`data() should return an object.`)
  884. } else if (instance.data === EMPTY_OBJ) {
  885. instance.data = reactive(data)
  886. } else {
  887. // existing data: this is a mixin or extends.
  888. if (
  889. __COMPAT__ &&
  890. isCompatEnabled(DeprecationTypes.OPTIONS_DATA_MERGE, instance)
  891. ) {
  892. deepMergeData(instance.data, data, instance)
  893. } else {
  894. extend(instance.data, data)
  895. }
  896. }
  897. }
  898. export function createWatcher(
  899. raw: ComponentWatchOptionItem,
  900. ctx: Data,
  901. publicThis: ComponentPublicInstance,
  902. key: string
  903. ) {
  904. const getter = key.includes('.')
  905. ? createPathGetter(publicThis, key)
  906. : () => (publicThis as any)[key]
  907. if (isString(raw)) {
  908. const handler = ctx[raw]
  909. if (isFunction(handler)) {
  910. watch(getter, handler as WatchCallback)
  911. } else if (__DEV__) {
  912. warn(`Invalid watch handler specified by key "${raw}"`, handler)
  913. }
  914. } else if (isFunction(raw)) {
  915. watch(getter, raw.bind(publicThis))
  916. } else if (isObject(raw)) {
  917. if (isArray(raw)) {
  918. raw.forEach(r => createWatcher(r, ctx, publicThis, key))
  919. } else {
  920. const handler = isFunction(raw.handler)
  921. ? raw.handler.bind(publicThis)
  922. : (ctx[raw.handler] as WatchCallback)
  923. if (isFunction(handler)) {
  924. watch(getter, handler, raw)
  925. } else if (__DEV__) {
  926. warn(`Invalid watch handler specified by key "${raw.handler}"`, handler)
  927. }
  928. }
  929. } else if (__DEV__) {
  930. warn(`Invalid watch option: "${key}"`, raw)
  931. }
  932. }
  933. export function resolveMergedOptions(
  934. instance: ComponentInternalInstance
  935. ): ComponentOptions {
  936. const raw = instance.type as ComponentOptions
  937. const { __merged, mixins, extends: extendsOptions } = raw
  938. if (__merged) return __merged
  939. const globalMixins = instance.appContext.mixins
  940. if (!globalMixins.length && !mixins && !extendsOptions) return raw
  941. const options = {}
  942. globalMixins.forEach(m => mergeOptions(options, m, instance))
  943. mergeOptions(options, raw, instance)
  944. return (raw.__merged = options)
  945. }
  946. export function mergeOptions(
  947. to: any,
  948. from: any,
  949. instance?: ComponentInternalInstance | null,
  950. strats = instance && instance.appContext.config.optionMergeStrategies
  951. ) {
  952. if (__COMPAT__ && isFunction(from)) {
  953. from = from.options
  954. }
  955. const { mixins, extends: extendsOptions } = from
  956. extendsOptions && mergeOptions(to, extendsOptions, instance, strats)
  957. mixins &&
  958. mixins.forEach((m: ComponentOptionsMixin) =>
  959. mergeOptions(to, m, instance, strats)
  960. )
  961. for (const key in from) {
  962. if (strats && hasOwn(strats, key)) {
  963. to[key] = strats[key](to[key], from[key], instance && instance.proxy, key)
  964. } else {
  965. to[key] = from[key]
  966. }
  967. }
  968. return to
  969. }