componentOptions.ts 24 KB

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