component.ts 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  1. import { type VNode, type VNodeChild, isVNode } from './vnode'
  2. import {
  3. EffectScope,
  4. type ReactiveEffect,
  5. TrackOpTypes,
  6. isRef,
  7. markRaw,
  8. pauseTracking,
  9. proxyRefs,
  10. resetTracking,
  11. shallowReadonly,
  12. track,
  13. } from '@vue/reactivity'
  14. import {
  15. type ComponentPublicInstance,
  16. type ComponentPublicInstanceConstructor,
  17. PublicInstanceProxyHandlers,
  18. RuntimeCompiledPublicInstanceProxyHandlers,
  19. createDevRenderContext,
  20. exposePropsOnRenderContext,
  21. exposeSetupStateOnRenderContext,
  22. publicPropertiesMap,
  23. } from './componentPublicInstance'
  24. import {
  25. type ComponentPropsOptions,
  26. type NormalizedPropsOptions,
  27. initProps,
  28. normalizePropsOptions,
  29. } from './componentProps'
  30. import {
  31. type InternalSlots,
  32. type Slots,
  33. type SlotsType,
  34. type UnwrapSlotsType,
  35. initSlots,
  36. } from './componentSlots'
  37. import { warn } from './warning'
  38. import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling'
  39. import {
  40. type AppConfig,
  41. type AppContext,
  42. createAppContext,
  43. } from './apiCreateApp'
  44. import { type Directive, validateDirectiveName } from './directives'
  45. import {
  46. type ComponentOptions,
  47. type ComputedOptions,
  48. type MergedComponentOptions,
  49. type MethodOptions,
  50. applyOptions,
  51. resolveMergedOptions,
  52. } from './componentOptions'
  53. import {
  54. type EmitFn,
  55. type EmitsOptions,
  56. type EmitsToProps,
  57. type ObjectEmitsOptions,
  58. type ShortEmitsToObject,
  59. emit,
  60. normalizeEmitsOptions,
  61. } from './componentEmits'
  62. import {
  63. EMPTY_OBJ,
  64. type IfAny,
  65. NOOP,
  66. ShapeFlags,
  67. extend,
  68. getGlobalThis,
  69. isArray,
  70. isFunction,
  71. isObject,
  72. isPromise,
  73. makeMap,
  74. } from '@vue/shared'
  75. import type { SuspenseBoundary } from './components/Suspense'
  76. import type { CompilerOptions } from '@vue/compiler-core'
  77. import { markAttrsAccessed } from './componentRenderUtils'
  78. import { currentRenderingInstance } from './componentRenderContext'
  79. import { endMeasure, startMeasure } from './profiling'
  80. import { convertLegacyRenderFn } from './compat/renderFn'
  81. import {
  82. type CompatConfig,
  83. globalCompatConfig,
  84. validateCompatConfig,
  85. } from './compat/compatConfig'
  86. import type { SchedulerJob } from './scheduler'
  87. import type { LifecycleHooks } from './enums'
  88. // Augment GlobalComponents
  89. import type { TeleportProps } from './components/Teleport'
  90. import type { SuspenseProps } from './components/Suspense'
  91. import type { KeepAliveProps } from './components/KeepAlive'
  92. import type { BaseTransitionProps } from './components/BaseTransition'
  93. import type { DefineComponent } from './apiDefineComponent'
  94. import { markAsyncBoundary } from './helpers/useId'
  95. import { isAsyncWrapper } from './apiAsyncComponent'
  96. import type { RendererElement } from './renderer'
  97. export type Data = Record<string, unknown>
  98. /**
  99. * Public utility type for extracting the instance type of a component.
  100. * Works with all valid component definition types. This is intended to replace
  101. * the usage of `InstanceType<typeof Comp>` which only works for
  102. * constructor-based component definition types.
  103. *
  104. * @example
  105. * ```ts
  106. * const MyComp = { ... }
  107. * declare const instance: ComponentInstance<typeof MyComp>
  108. * ```
  109. */
  110. export type ComponentInstance<T> = T extends { new (): ComponentPublicInstance }
  111. ? InstanceType<T>
  112. : T extends FunctionalComponent<infer Props, infer Emits>
  113. ? ComponentPublicInstance<Props, {}, {}, {}, {}, ShortEmitsToObject<Emits>>
  114. : T extends Component<
  115. infer PropsOrInstance,
  116. infer RawBindings,
  117. infer D,
  118. infer C,
  119. infer M
  120. >
  121. ? PropsOrInstance extends { $props: unknown }
  122. ? // T is returned by `defineComponent()`
  123. PropsOrInstance
  124. : // NOTE we override Props/RawBindings/D to make sure is not `unknown`
  125. ComponentPublicInstance<
  126. unknown extends PropsOrInstance ? {} : PropsOrInstance,
  127. unknown extends RawBindings ? {} : RawBindings,
  128. unknown extends D ? {} : D,
  129. C,
  130. M
  131. >
  132. : never // not a vue Component
  133. /**
  134. * For extending allowed non-declared props on components in TSX
  135. */
  136. export interface ComponentCustomProps {}
  137. /**
  138. * For globally defined Directives
  139. * Here is an example of adding a directive `VTooltip` as global directive:
  140. *
  141. * @example
  142. * ```ts
  143. * import VTooltip from 'v-tooltip'
  144. *
  145. * declare module '@vue/runtime-core' {
  146. * interface GlobalDirectives {
  147. * VTooltip
  148. * }
  149. * }
  150. * ```
  151. */
  152. export interface GlobalDirectives {}
  153. /**
  154. * For globally defined Components
  155. * Here is an example of adding a component `RouterView` as global component:
  156. *
  157. * @example
  158. * ```ts
  159. * import { RouterView } from 'vue-router'
  160. *
  161. * declare module '@vue/runtime-core' {
  162. * interface GlobalComponents {
  163. * RouterView
  164. * }
  165. * }
  166. * ```
  167. */
  168. export interface GlobalComponents {
  169. Teleport: DefineComponent<TeleportProps>
  170. Suspense: DefineComponent<SuspenseProps>
  171. KeepAlive: DefineComponent<KeepAliveProps>
  172. BaseTransition: DefineComponent<BaseTransitionProps>
  173. }
  174. /**
  175. * Default allowed non-declared props on component in TSX
  176. */
  177. export interface AllowedComponentProps {
  178. class?: unknown
  179. style?: unknown
  180. }
  181. // Note: can't mark this whole interface internal because some public interfaces
  182. // extend it.
  183. export interface ComponentInternalOptions {
  184. /**
  185. * @internal
  186. */
  187. __scopeId?: string
  188. /**
  189. * @internal
  190. */
  191. __cssModules?: Data
  192. /**
  193. * @internal
  194. */
  195. __hmrId?: string
  196. /**
  197. * Compat build only, for bailing out of certain compatibility behavior
  198. */
  199. __isBuiltIn?: boolean
  200. /**
  201. * This one should be exposed so that devtools can make use of it
  202. */
  203. __file?: string
  204. /**
  205. * name inferred from filename
  206. */
  207. __name?: string
  208. }
  209. export interface FunctionalComponent<
  210. P = {},
  211. E extends EmitsOptions | Record<string, any[]> = {},
  212. S extends Record<string, any> = any,
  213. EE extends EmitsOptions = ShortEmitsToObject<E>,
  214. > extends ComponentInternalOptions {
  215. // use of any here is intentional so it can be a valid JSX Element constructor
  216. (
  217. props: P & EmitsToProps<EE>,
  218. ctx: Omit<SetupContext<EE, IfAny<S, {}, SlotsType<S>>>, 'expose'>,
  219. ): any
  220. props?: ComponentPropsOptions<P>
  221. emits?: EE | (keyof EE)[]
  222. slots?: IfAny<S, Slots, SlotsType<S>>
  223. inheritAttrs?: boolean
  224. displayName?: string
  225. compatConfig?: CompatConfig
  226. }
  227. export interface ClassComponent {
  228. new (...args: any[]): ComponentPublicInstance<any, any, any, any, any>
  229. __vccOpts: ComponentOptions
  230. }
  231. /**
  232. * Concrete component type matches its actual value: it's either an options
  233. * object, or a function. Use this where the code expects to work with actual
  234. * values, e.g. checking if its a function or not. This is mostly for internal
  235. * implementation code.
  236. */
  237. export type ConcreteComponent<
  238. Props = {},
  239. RawBindings = any,
  240. D = any,
  241. C extends ComputedOptions = ComputedOptions,
  242. M extends MethodOptions = MethodOptions,
  243. E extends EmitsOptions | Record<string, any[]> = {},
  244. S extends Record<string, any> = any,
  245. > =
  246. | ComponentOptions<Props, RawBindings, D, C, M>
  247. | FunctionalComponent<Props, E, S>
  248. /**
  249. * A type used in public APIs where a component type is expected.
  250. * The constructor type is an artificial type returned by defineComponent().
  251. */
  252. export type Component<
  253. PropsOrInstance = any,
  254. RawBindings = any,
  255. D = any,
  256. C extends ComputedOptions = ComputedOptions,
  257. M extends MethodOptions = MethodOptions,
  258. E extends EmitsOptions | Record<string, any[]> = {},
  259. S extends Record<string, any> = any,
  260. > =
  261. | ConcreteComponent<PropsOrInstance, RawBindings, D, C, M, E, S>
  262. | ComponentPublicInstanceConstructor<PropsOrInstance>
  263. export type { ComponentOptions }
  264. export type LifecycleHook<TFn = Function> = (TFn & SchedulerJob)[] | null
  265. // use `E extends any` to force evaluating type to fix #2362
  266. export type SetupContext<
  267. E = EmitsOptions,
  268. S extends SlotsType = {},
  269. > = E extends any
  270. ? {
  271. attrs: Data
  272. slots: UnwrapSlotsType<S>
  273. emit: EmitFn<E>
  274. expose: <Exposed extends Record<string, any> = Record<string, any>>(
  275. exposed?: Exposed,
  276. ) => void
  277. }
  278. : never
  279. /**
  280. * @internal
  281. */
  282. export type InternalRenderFunction = {
  283. (
  284. ctx: ComponentPublicInstance,
  285. cache: ComponentInternalInstance['renderCache'],
  286. // for compiler-optimized bindings
  287. $props: ComponentInternalInstance['props'],
  288. $setup: ComponentInternalInstance['setupState'],
  289. $data: ComponentInternalInstance['data'],
  290. $options: ComponentInternalInstance['ctx'],
  291. ): VNodeChild
  292. _rc?: boolean // isRuntimeCompiled
  293. // __COMPAT__ only
  294. _compatChecked?: boolean // v3 and already checked for v2 compat
  295. _compatWrapped?: boolean // is wrapped for v2 compat
  296. }
  297. /**
  298. * We expose a subset of properties on the internal instance as they are
  299. * useful for advanced external libraries and tools.
  300. */
  301. export interface ComponentInternalInstance {
  302. uid: number
  303. type: ConcreteComponent
  304. parent: ComponentInternalInstance | null
  305. root: ComponentInternalInstance
  306. appContext: AppContext
  307. /**
  308. * Vnode representing this component in its parent's vdom tree
  309. */
  310. vnode: VNode
  311. /**
  312. * The pending new vnode from parent updates
  313. * @internal
  314. */
  315. next: VNode | null
  316. /**
  317. * Root vnode of this component's own vdom tree
  318. */
  319. subTree: VNode
  320. /**
  321. * Render effect instance
  322. */
  323. effect: ReactiveEffect
  324. /**
  325. * Force update render effect
  326. */
  327. update: () => void
  328. /**
  329. * Render effect job to be passed to scheduler (checks if dirty)
  330. */
  331. job: SchedulerJob
  332. /**
  333. * The render function that returns vdom tree.
  334. * @internal
  335. */
  336. render: InternalRenderFunction | null
  337. /**
  338. * SSR render function
  339. * @internal
  340. */
  341. ssrRender?: Function | null
  342. /**
  343. * Object containing values this component provides for its descendants
  344. * @internal
  345. */
  346. provides: Data
  347. /**
  348. * for tracking useId()
  349. * first element is the current boundary prefix
  350. * second number is the index of the useId call within that boundary
  351. * @internal
  352. */
  353. ids: [string, number, number]
  354. /**
  355. * Tracking reactive effects (e.g. watchers) associated with this component
  356. * so that they can be automatically stopped on component unmount
  357. * @internal
  358. */
  359. scope: EffectScope
  360. /**
  361. * cache for proxy access type to avoid hasOwnProperty calls
  362. * @internal
  363. */
  364. accessCache: Data | null
  365. /**
  366. * cache for render function values that rely on _ctx but won't need updates
  367. * after initialized (e.g. inline handlers)
  368. * @internal
  369. */
  370. renderCache: (Function | VNode | undefined)[]
  371. /**
  372. * Resolved component registry, only for components with mixins or extends
  373. * @internal
  374. */
  375. components: Record<string, ConcreteComponent> | null
  376. /**
  377. * Resolved directive registry, only for components with mixins or extends
  378. * @internal
  379. */
  380. directives: Record<string, Directive> | null
  381. /**
  382. * Resolved filters registry, v2 compat only
  383. * @internal
  384. */
  385. filters?: Record<string, Function>
  386. /**
  387. * resolved props options
  388. * @internal
  389. */
  390. propsOptions: NormalizedPropsOptions
  391. /**
  392. * resolved emits options
  393. * @internal
  394. */
  395. emitsOptions: ObjectEmitsOptions | null
  396. /**
  397. * resolved inheritAttrs options
  398. * @internal
  399. */
  400. inheritAttrs?: boolean
  401. /**
  402. * Custom Element instance (if component is created by defineCustomElement)
  403. * @internal
  404. */
  405. ce?: ComponentCustomElementInterface
  406. /**
  407. * is custom element? (kept only for compatibility)
  408. * @internal
  409. */
  410. isCE?: boolean
  411. /**
  412. * custom element specific HMR method
  413. * @internal
  414. */
  415. ceReload?: (newStyles?: string[]) => void
  416. // the rest are only for stateful components ---------------------------------
  417. // main proxy that serves as the public instance (`this`)
  418. proxy: ComponentPublicInstance | null
  419. // exposed properties via expose()
  420. exposed: Record<string, any> | null
  421. exposeProxy: Record<string, any> | null
  422. /**
  423. * alternative proxy used only for runtime-compiled render functions using
  424. * `with` block
  425. * @internal
  426. */
  427. withProxy: ComponentPublicInstance | null
  428. /**
  429. * This is the target for the public instance proxy. It also holds properties
  430. * injected by user options (computed, methods etc.) and user-attached
  431. * custom properties (via `this.x = ...`)
  432. * @internal
  433. */
  434. ctx: Data
  435. // state
  436. data: Data
  437. props: Data
  438. attrs: Data
  439. slots: InternalSlots
  440. refs: Data
  441. emit: EmitFn
  442. /**
  443. * used for keeping track of .once event handlers on components
  444. * @internal
  445. */
  446. emitted: Record<string, boolean> | null
  447. /**
  448. * used for caching the value returned from props default factory functions to
  449. * avoid unnecessary watcher trigger
  450. * @internal
  451. */
  452. propsDefaults: Data
  453. /**
  454. * setup related
  455. * @internal
  456. */
  457. setupState: Data
  458. /**
  459. * devtools access to additional info
  460. * @internal
  461. */
  462. devtoolsRawSetupState?: any
  463. /**
  464. * @internal
  465. */
  466. setupContext: SetupContext | null
  467. /**
  468. * suspense related
  469. * @internal
  470. */
  471. suspense: SuspenseBoundary | null
  472. /**
  473. * suspense pending batch id
  474. * @internal
  475. */
  476. suspenseId: number
  477. /**
  478. * @internal
  479. */
  480. asyncDep: Promise<any> | null
  481. /**
  482. * @internal
  483. */
  484. asyncResolved: boolean
  485. // lifecycle
  486. isMounted: boolean
  487. isUnmounted: boolean
  488. isDeactivated: boolean
  489. /**
  490. * @internal
  491. */
  492. [LifecycleHooks.BEFORE_CREATE]: LifecycleHook
  493. /**
  494. * @internal
  495. */
  496. [LifecycleHooks.CREATED]: LifecycleHook
  497. /**
  498. * @internal
  499. */
  500. [LifecycleHooks.BEFORE_MOUNT]: LifecycleHook
  501. /**
  502. * @internal
  503. */
  504. [LifecycleHooks.MOUNTED]: LifecycleHook
  505. /**
  506. * @internal
  507. */
  508. [LifecycleHooks.BEFORE_UPDATE]: LifecycleHook
  509. /**
  510. * @internal
  511. */
  512. [LifecycleHooks.UPDATED]: LifecycleHook
  513. /**
  514. * @internal
  515. */
  516. [LifecycleHooks.BEFORE_UNMOUNT]: LifecycleHook
  517. /**
  518. * @internal
  519. */
  520. [LifecycleHooks.UNMOUNTED]: LifecycleHook
  521. /**
  522. * @internal
  523. */
  524. [LifecycleHooks.RENDER_TRACKED]: LifecycleHook
  525. /**
  526. * @internal
  527. */
  528. [LifecycleHooks.RENDER_TRIGGERED]: LifecycleHook
  529. /**
  530. * @internal
  531. */
  532. [LifecycleHooks.ACTIVATED]: LifecycleHook
  533. /**
  534. * @internal
  535. */
  536. [LifecycleHooks.DEACTIVATED]: LifecycleHook
  537. /**
  538. * @internal
  539. */
  540. [LifecycleHooks.ERROR_CAPTURED]: LifecycleHook
  541. /**
  542. * @internal
  543. */
  544. [LifecycleHooks.SERVER_PREFETCH]: LifecycleHook<() => Promise<unknown>>
  545. /**
  546. * For caching bound $forceUpdate on public proxy access
  547. * @internal
  548. */
  549. f?: () => void
  550. /**
  551. * For caching bound $nextTick on public proxy access
  552. * @internal
  553. */
  554. n?: () => Promise<void>
  555. /**
  556. * `updateTeleportCssVars`
  557. * For updating css vars on contained teleports
  558. * @internal
  559. */
  560. ut?: (vars?: Record<string, string>) => void
  561. /**
  562. * dev only. For style v-bind hydration mismatch checks
  563. * @internal
  564. */
  565. getCssVars?: () => Record<string, string>
  566. /**
  567. * v2 compat only, for caching mutated $options
  568. * @internal
  569. */
  570. resolvedOptions?: MergedComponentOptions
  571. }
  572. const emptyAppContext = createAppContext()
  573. let uid = 0
  574. export function createComponentInstance(
  575. vnode: VNode,
  576. parent: ComponentInternalInstance | null,
  577. suspense: SuspenseBoundary | null,
  578. ): ComponentInternalInstance {
  579. const type = vnode.type as ConcreteComponent
  580. // inherit parent app context - or - if root, adopt from root vnode
  581. const appContext =
  582. (parent ? parent.appContext : vnode.appContext) || emptyAppContext
  583. const instance: ComponentInternalInstance = {
  584. uid: uid++,
  585. vnode,
  586. type,
  587. parent,
  588. appContext,
  589. root: null!, // to be immediately set
  590. next: null,
  591. subTree: null!, // will be set synchronously right after creation
  592. effect: null!,
  593. update: null!, // will be set synchronously right after creation
  594. job: null!,
  595. scope: new EffectScope(true /* detached */),
  596. render: null,
  597. proxy: null,
  598. exposed: null,
  599. exposeProxy: null,
  600. withProxy: null,
  601. provides: parent ? parent.provides : Object.create(appContext.provides),
  602. ids: parent ? parent.ids : ['', 0, 0],
  603. accessCache: null!,
  604. renderCache: [],
  605. // local resolved assets
  606. components: null,
  607. directives: null,
  608. // resolved props and emits options
  609. propsOptions: normalizePropsOptions(type, appContext),
  610. emitsOptions: normalizeEmitsOptions(type, appContext),
  611. // emit
  612. emit: null!, // to be set immediately
  613. emitted: null,
  614. // props default value
  615. propsDefaults: EMPTY_OBJ,
  616. // inheritAttrs
  617. inheritAttrs: type.inheritAttrs,
  618. // state
  619. ctx: EMPTY_OBJ,
  620. data: EMPTY_OBJ,
  621. props: EMPTY_OBJ,
  622. attrs: EMPTY_OBJ,
  623. slots: EMPTY_OBJ,
  624. refs: EMPTY_OBJ,
  625. setupState: EMPTY_OBJ,
  626. setupContext: null,
  627. // suspense related
  628. suspense,
  629. suspenseId: suspense ? suspense.pendingId : 0,
  630. asyncDep: null,
  631. asyncResolved: false,
  632. // lifecycle hooks
  633. // not using enums here because it results in computed properties
  634. isMounted: false,
  635. isUnmounted: false,
  636. isDeactivated: false,
  637. bc: null,
  638. c: null,
  639. bm: null,
  640. m: null,
  641. bu: null,
  642. u: null,
  643. um: null,
  644. bum: null,
  645. da: null,
  646. a: null,
  647. rtg: null,
  648. rtc: null,
  649. ec: null,
  650. sp: null,
  651. }
  652. if (__DEV__) {
  653. instance.ctx = createDevRenderContext(instance)
  654. } else {
  655. instance.ctx = { _: instance }
  656. }
  657. instance.root = parent ? parent.root : instance
  658. instance.emit = emit.bind(null, instance)
  659. // apply custom element special handling
  660. if (vnode.ce) {
  661. vnode.ce(instance)
  662. }
  663. return instance
  664. }
  665. export let currentInstance: ComponentInternalInstance | null = null
  666. export const getCurrentInstance: () => ComponentInternalInstance | null = () =>
  667. currentInstance || currentRenderingInstance
  668. let internalSetCurrentInstance: (
  669. instance: ComponentInternalInstance | null,
  670. ) => void
  671. let setInSSRSetupState: (state: boolean) => void
  672. /**
  673. * The following makes getCurrentInstance() usage across multiple copies of Vue
  674. * work. Some cases of how this can happen are summarized in #7590. In principle
  675. * the duplication should be avoided, but in practice there are often cases
  676. * where the user is unable to resolve on their own, especially in complicated
  677. * SSR setups.
  678. *
  679. * Note this fix is technically incomplete, as we still rely on other singletons
  680. * for effectScope and global reactive dependency maps. However, it does make
  681. * some of the most common cases work. It also warns if the duplication is
  682. * found during browser execution.
  683. */
  684. if (__SSR__) {
  685. type Setter = (v: any) => void
  686. const g = getGlobalThis()
  687. const registerGlobalSetter = (key: string, setter: Setter) => {
  688. let setters: Setter[]
  689. if (!(setters = g[key])) setters = g[key] = []
  690. setters.push(setter)
  691. return (v: any) => {
  692. if (setters.length > 1) setters.forEach(set => set(v))
  693. else setters[0](v)
  694. }
  695. }
  696. internalSetCurrentInstance = registerGlobalSetter(
  697. `__VUE_INSTANCE_SETTERS__`,
  698. v => (currentInstance = v),
  699. )
  700. // also make `isInSSRComponentSetup` sharable across copies of Vue.
  701. // this is needed in the SFC playground when SSRing async components, since
  702. // we have to load both the runtime and the server-renderer from CDNs, they
  703. // contain duplicated copies of Vue runtime code.
  704. setInSSRSetupState = registerGlobalSetter(
  705. `__VUE_SSR_SETTERS__`,
  706. v => (isInSSRComponentSetup = v),
  707. )
  708. } else {
  709. internalSetCurrentInstance = i => {
  710. currentInstance = i
  711. }
  712. setInSSRSetupState = v => {
  713. isInSSRComponentSetup = v
  714. }
  715. }
  716. export const setCurrentInstance = (instance: ComponentInternalInstance) => {
  717. const prev = currentInstance
  718. internalSetCurrentInstance(instance)
  719. instance.scope.on()
  720. return (): void => {
  721. instance.scope.off()
  722. internalSetCurrentInstance(prev)
  723. }
  724. }
  725. export const unsetCurrentInstance = (): void => {
  726. currentInstance && currentInstance.scope.off()
  727. internalSetCurrentInstance(null)
  728. }
  729. const isBuiltInTag = /*@__PURE__*/ makeMap('slot,component')
  730. export function validateComponentName(
  731. name: string,
  732. { isNativeTag }: AppConfig,
  733. ): void {
  734. if (isBuiltInTag(name) || isNativeTag(name)) {
  735. warn(
  736. 'Do not use built-in or reserved HTML elements as component id: ' + name,
  737. )
  738. }
  739. }
  740. export function isStatefulComponent(
  741. instance: ComponentInternalInstance,
  742. ): number {
  743. return instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT
  744. }
  745. export let isInSSRComponentSetup = false
  746. export function setupComponent(
  747. instance: ComponentInternalInstance,
  748. isSSR = false,
  749. optimized = false,
  750. ): Promise<void> | undefined {
  751. isSSR && setInSSRSetupState(isSSR)
  752. const { props, children } = instance.vnode
  753. const isStateful = isStatefulComponent(instance)
  754. initProps(instance, props, isStateful, isSSR)
  755. initSlots(instance, children, optimized || isSSR)
  756. const setupResult = isStateful
  757. ? setupStatefulComponent(instance, isSSR)
  758. : undefined
  759. isSSR && setInSSRSetupState(false)
  760. return setupResult
  761. }
  762. function setupStatefulComponent(
  763. instance: ComponentInternalInstance,
  764. isSSR: boolean,
  765. ) {
  766. const Component = instance.type as ComponentOptions
  767. if (__DEV__) {
  768. if (Component.name) {
  769. validateComponentName(Component.name, instance.appContext.config)
  770. }
  771. if (Component.components) {
  772. const names = Object.keys(Component.components)
  773. for (let i = 0; i < names.length; i++) {
  774. validateComponentName(names[i], instance.appContext.config)
  775. }
  776. }
  777. if (Component.directives) {
  778. const names = Object.keys(Component.directives)
  779. for (let i = 0; i < names.length; i++) {
  780. validateDirectiveName(names[i])
  781. }
  782. }
  783. if (Component.compilerOptions && isRuntimeOnly()) {
  784. warn(
  785. `"compilerOptions" is only supported when using a build of Vue that ` +
  786. `includes the runtime compiler. Since you are using a runtime-only ` +
  787. `build, the options should be passed via your build tool config instead.`,
  788. )
  789. }
  790. }
  791. // 0. create render proxy property access cache
  792. instance.accessCache = Object.create(null)
  793. // 1. create public instance / render proxy
  794. instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers)
  795. if (__DEV__) {
  796. exposePropsOnRenderContext(instance)
  797. }
  798. // 2. call setup()
  799. const { setup } = Component
  800. if (setup) {
  801. pauseTracking()
  802. const setupContext = (instance.setupContext =
  803. setup.length > 1 ? createSetupContext(instance) : null)
  804. const reset = setCurrentInstance(instance)
  805. const setupResult = callWithErrorHandling(
  806. setup,
  807. instance,
  808. ErrorCodes.SETUP_FUNCTION,
  809. [
  810. __DEV__ ? shallowReadonly(instance.props) : instance.props,
  811. setupContext,
  812. ],
  813. )
  814. const isAsyncSetup = isPromise(setupResult)
  815. resetTracking()
  816. reset()
  817. if ((isAsyncSetup || instance.sp) && !isAsyncWrapper(instance)) {
  818. // async setup / serverPrefetch, mark as async boundary for useId()
  819. markAsyncBoundary(instance)
  820. }
  821. if (isAsyncSetup) {
  822. setupResult.then(unsetCurrentInstance, unsetCurrentInstance)
  823. if (isSSR) {
  824. // return the promise so server-renderer can wait on it
  825. return setupResult
  826. .then((resolvedResult: unknown) => {
  827. handleSetupResult(instance, resolvedResult, isSSR)
  828. })
  829. .catch(e => {
  830. handleError(e, instance, ErrorCodes.SETUP_FUNCTION)
  831. })
  832. } else if (__FEATURE_SUSPENSE__) {
  833. // async setup returned Promise.
  834. // bail here and wait for re-entry.
  835. instance.asyncDep = setupResult
  836. if (__DEV__ && !instance.suspense) {
  837. const name = Component.name ?? 'Anonymous'
  838. warn(
  839. `Component <${name}>: setup function returned a promise, but no ` +
  840. `<Suspense> boundary was found in the parent component tree. ` +
  841. `A component with async setup() must be nested in a <Suspense> ` +
  842. `in order to be rendered.`,
  843. )
  844. }
  845. } else if (__DEV__) {
  846. warn(
  847. `setup() returned a Promise, but the version of Vue you are using ` +
  848. `does not support it yet.`,
  849. )
  850. }
  851. } else {
  852. handleSetupResult(instance, setupResult, isSSR)
  853. }
  854. } else {
  855. finishComponentSetup(instance, isSSR)
  856. }
  857. }
  858. export function handleSetupResult(
  859. instance: ComponentInternalInstance,
  860. setupResult: unknown,
  861. isSSR: boolean,
  862. ): void {
  863. if (isFunction(setupResult)) {
  864. // setup returned an inline render function
  865. if (__SSR__ && (instance.type as ComponentOptions).__ssrInlineRender) {
  866. // when the function's name is `ssrRender` (compiled by SFC inline mode),
  867. // set it as ssrRender instead.
  868. instance.ssrRender = setupResult
  869. } else {
  870. instance.render = setupResult as InternalRenderFunction
  871. }
  872. } else if (isObject(setupResult)) {
  873. if (__DEV__ && isVNode(setupResult)) {
  874. warn(
  875. `setup() should not return VNodes directly - ` +
  876. `return a render function instead.`,
  877. )
  878. }
  879. // setup returned bindings.
  880. // assuming a render function compiled from template is present.
  881. if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
  882. instance.devtoolsRawSetupState = setupResult
  883. }
  884. instance.setupState = proxyRefs(setupResult)
  885. if (__DEV__) {
  886. exposeSetupStateOnRenderContext(instance)
  887. }
  888. } else if (__DEV__ && setupResult !== undefined) {
  889. warn(
  890. `setup() should return an object. Received: ${
  891. setupResult === null ? 'null' : typeof setupResult
  892. }`,
  893. )
  894. }
  895. finishComponentSetup(instance, isSSR)
  896. }
  897. type CompileFunction = (
  898. template: string | object,
  899. options?: CompilerOptions,
  900. ) => InternalRenderFunction
  901. let compile: CompileFunction | undefined
  902. let installWithProxy: (i: ComponentInternalInstance) => void
  903. /**
  904. * For runtime-dom to register the compiler.
  905. * Note the exported method uses any to avoid d.ts relying on the compiler types.
  906. */
  907. export function registerRuntimeCompiler(_compile: any): void {
  908. compile = _compile
  909. installWithProxy = i => {
  910. if (i.render!._rc) {
  911. i.withProxy = new Proxy(i.ctx, RuntimeCompiledPublicInstanceProxyHandlers)
  912. }
  913. }
  914. }
  915. // dev only
  916. export const isRuntimeOnly = (): boolean => !compile
  917. export function finishComponentSetup(
  918. instance: ComponentInternalInstance,
  919. isSSR: boolean,
  920. skipOptions?: boolean,
  921. ): void {
  922. const Component = instance.type as ComponentOptions
  923. if (__COMPAT__) {
  924. convertLegacyRenderFn(instance)
  925. if (__DEV__ && Component.compatConfig) {
  926. validateCompatConfig(Component.compatConfig)
  927. }
  928. }
  929. // template / render function normalization
  930. // could be already set when returned from setup()
  931. if (!instance.render) {
  932. // only do on-the-fly compile if not in SSR - SSR on-the-fly compilation
  933. // is done by server-renderer
  934. if (!isSSR && compile && !Component.render) {
  935. const template =
  936. (__COMPAT__ &&
  937. instance.vnode.props &&
  938. instance.vnode.props['inline-template']) ||
  939. Component.template ||
  940. (__FEATURE_OPTIONS_API__ && resolveMergedOptions(instance).template)
  941. if (template) {
  942. if (__DEV__) {
  943. startMeasure(instance, `compile`)
  944. }
  945. const { isCustomElement, compilerOptions } = instance.appContext.config
  946. const { delimiters, compilerOptions: componentCompilerOptions } =
  947. Component
  948. const finalCompilerOptions: CompilerOptions = extend(
  949. extend(
  950. {
  951. isCustomElement,
  952. delimiters,
  953. },
  954. compilerOptions,
  955. ),
  956. componentCompilerOptions,
  957. )
  958. if (__COMPAT__) {
  959. // pass runtime compat config into the compiler
  960. finalCompilerOptions.compatConfig = Object.create(globalCompatConfig)
  961. if (Component.compatConfig) {
  962. // @ts-expect-error types are not compatible
  963. extend(finalCompilerOptions.compatConfig, Component.compatConfig)
  964. }
  965. }
  966. Component.render = compile(template, finalCompilerOptions)
  967. if (__DEV__) {
  968. endMeasure(instance, `compile`)
  969. }
  970. }
  971. }
  972. instance.render = (Component.render || NOOP) as InternalRenderFunction
  973. // for runtime-compiled render functions using `with` blocks, the render
  974. // proxy used needs a different `has` handler which is more performant and
  975. // also only allows a whitelist of globals to fallthrough.
  976. if (installWithProxy) {
  977. installWithProxy(instance)
  978. }
  979. }
  980. // support for 2.x options
  981. if (__FEATURE_OPTIONS_API__ && !(__COMPAT__ && skipOptions)) {
  982. const reset = setCurrentInstance(instance)
  983. pauseTracking()
  984. try {
  985. applyOptions(instance)
  986. } finally {
  987. resetTracking()
  988. reset()
  989. }
  990. }
  991. // warn missing template/render
  992. // the runtime compilation of template in SSR is done by server-render
  993. if (__DEV__ && !Component.render && instance.render === NOOP && !isSSR) {
  994. if (!compile && Component.template) {
  995. /* v8 ignore start */
  996. warn(
  997. `Component provided template option but ` +
  998. `runtime compilation is not supported in this build of Vue.` +
  999. (__ESM_BUNDLER__
  1000. ? ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".`
  1001. : __ESM_BROWSER__
  1002. ? ` Use "vue.esm-browser.js" instead.`
  1003. : __GLOBAL__
  1004. ? ` Use "vue.global.js" instead.`
  1005. : ``) /* should not happen */,
  1006. )
  1007. /* v8 ignore stop */
  1008. } else {
  1009. warn(`Component is missing template or render function: `, Component)
  1010. }
  1011. }
  1012. }
  1013. const attrsProxyHandlers = __DEV__
  1014. ? {
  1015. get(target: Data, key: string) {
  1016. markAttrsAccessed()
  1017. track(target, TrackOpTypes.GET, '')
  1018. return target[key]
  1019. },
  1020. set() {
  1021. warn(`setupContext.attrs is readonly.`)
  1022. return false
  1023. },
  1024. deleteProperty() {
  1025. warn(`setupContext.attrs is readonly.`)
  1026. return false
  1027. },
  1028. }
  1029. : {
  1030. get(target: Data, key: string) {
  1031. track(target, TrackOpTypes.GET, '')
  1032. return target[key]
  1033. },
  1034. }
  1035. /**
  1036. * Dev-only
  1037. */
  1038. function getSlotsProxy(instance: ComponentInternalInstance): Slots {
  1039. return new Proxy(instance.slots, {
  1040. get(target, key: string) {
  1041. track(instance, TrackOpTypes.GET, '$slots')
  1042. return target[key]
  1043. },
  1044. })
  1045. }
  1046. export function createSetupContext(
  1047. instance: ComponentInternalInstance,
  1048. ): SetupContext {
  1049. const expose: SetupContext['expose'] = exposed => {
  1050. if (__DEV__) {
  1051. if (instance.exposed) {
  1052. warn(`expose() should be called only once per setup().`)
  1053. }
  1054. if (exposed != null) {
  1055. let exposedType: string = typeof exposed
  1056. if (exposedType === 'object') {
  1057. if (isArray(exposed)) {
  1058. exposedType = 'array'
  1059. } else if (isRef(exposed)) {
  1060. exposedType = 'ref'
  1061. }
  1062. }
  1063. if (exposedType !== 'object') {
  1064. warn(
  1065. `expose() should be passed a plain object, received ${exposedType}.`,
  1066. )
  1067. }
  1068. }
  1069. }
  1070. instance.exposed = exposed || {}
  1071. }
  1072. if (__DEV__) {
  1073. // We use getters in dev in case libs like test-utils overwrite instance
  1074. // properties (overwrites should not be done in prod)
  1075. let attrsProxy: Data
  1076. let slotsProxy: Slots
  1077. return Object.freeze({
  1078. get attrs() {
  1079. return (
  1080. attrsProxy ||
  1081. (attrsProxy = new Proxy(instance.attrs, attrsProxyHandlers))
  1082. )
  1083. },
  1084. get slots() {
  1085. return slotsProxy || (slotsProxy = getSlotsProxy(instance))
  1086. },
  1087. get emit() {
  1088. return (event: string, ...args: any[]) => instance.emit(event, ...args)
  1089. },
  1090. expose,
  1091. })
  1092. } else {
  1093. return {
  1094. attrs: new Proxy(instance.attrs, attrsProxyHandlers),
  1095. slots: instance.slots,
  1096. emit: instance.emit,
  1097. expose,
  1098. }
  1099. }
  1100. }
  1101. export function getComponentPublicInstance(
  1102. instance: ComponentInternalInstance,
  1103. ): ComponentPublicInstance | ComponentInternalInstance['exposed'] | null {
  1104. if (instance.exposed) {
  1105. return (
  1106. instance.exposeProxy ||
  1107. (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
  1108. get(target, key: string) {
  1109. if (key in target) {
  1110. return target[key]
  1111. } else if (key in publicPropertiesMap) {
  1112. return publicPropertiesMap[key](instance)
  1113. }
  1114. },
  1115. has(target, key: string) {
  1116. return key in target || key in publicPropertiesMap
  1117. },
  1118. }))
  1119. )
  1120. } else {
  1121. return instance.proxy
  1122. }
  1123. }
  1124. const classifyRE = /(?:^|[-_])(\w)/g
  1125. const classify = (str: string): string =>
  1126. str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '')
  1127. export function getComponentName(
  1128. Component: ConcreteComponent,
  1129. includeInferred = true,
  1130. ): string | false | undefined {
  1131. return isFunction(Component)
  1132. ? Component.displayName || Component.name
  1133. : Component.name || (includeInferred && Component.__name)
  1134. }
  1135. export function formatComponentName(
  1136. instance: ComponentInternalInstance | null,
  1137. Component: ConcreteComponent,
  1138. isRoot = false,
  1139. ): string {
  1140. let name = getComponentName(Component)
  1141. if (!name && Component.__file) {
  1142. const match = Component.__file.match(/([^/\\]+)\.\w+$/)
  1143. if (match) {
  1144. name = match[1]
  1145. }
  1146. }
  1147. if (!name && instance && instance.parent) {
  1148. // try to infer the name based on reverse resolution
  1149. const inferFromRegistry = (registry: Record<string, any> | undefined) => {
  1150. for (const key in registry) {
  1151. if (registry[key] === Component) {
  1152. return key
  1153. }
  1154. }
  1155. }
  1156. name =
  1157. inferFromRegistry(
  1158. instance.components ||
  1159. (instance.parent.type as ComponentOptions).components,
  1160. ) || inferFromRegistry(instance.appContext.components)
  1161. }
  1162. return name ? classify(name) : isRoot ? `App` : `Anonymous`
  1163. }
  1164. export function isClassComponent(value: unknown): value is ClassComponent {
  1165. return isFunction(value) && '__vccOpts' in value
  1166. }
  1167. export interface ComponentCustomElementInterface {
  1168. /**
  1169. * @internal
  1170. */
  1171. _injectChildStyle(type: ConcreteComponent): void
  1172. /**
  1173. * @internal
  1174. */
  1175. _removeChildStyle(type: ConcreteComponent): void
  1176. /**
  1177. * @internal
  1178. */
  1179. _setProp(
  1180. key: string,
  1181. val: any,
  1182. shouldReflect?: boolean,
  1183. shouldUpdate?: boolean,
  1184. ): void
  1185. /**
  1186. * @internal attached by the nested Teleport when shadowRoot is false.
  1187. */
  1188. _teleportTarget?: RendererElement
  1189. }