import { warn } from './warning'
import { ErrorCodes, callWithErrorHandling } from './errorHandling'
import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
-import { Directive, validateDirectiveName } from './directives'
+import { validateDirectiveName } from './directives'
import { applyOptions, ComponentOptions } from './componentOptions'
import {
EmitsOptions,
*/
renderCache: (Function | VNode)[]
- /**
- * Asset hashes that prototypally inherits app-level asset hashes for fast
- * resolution
- * @internal
- */
- components: Record<string, Component>
- /**
- * @internal
- */
- directives: Record<string, Directive>
-
// the rest are only for stateful components ---------------------------------
// main proxy that serves as the public instance (`this`)
parent: ComponentInternalInstance | null,
suspense: SuspenseBoundary | null
) {
+ const type = vnode.type as Component
// inherit parent app context - or - if root, adopt from root vnode
const appContext =
(parent ? parent.appContext : vnode.appContext) || emptyAppContext
+
const instance: ComponentInternalInstance = {
uid: uid++,
vnode,
+ type,
parent,
appContext,
- type: vnode.type as Component,
root: null!, // to be immediately set
next: null,
subTree: null!, // will be set synchronously right after creation
setupState: EMPTY_OBJ,
setupContext: null,
- // per-instance asset storage (mutable during options resolution)
- components: Object.create(appContext.components),
- directives: Object.create(appContext.directives),
-
// suspense related
suspense,
asyncDep: null,
}
if (!name && instance && instance.parent) {
- // try to infer the name based on local resolution
- const registry = instance.parent.components
- for (const key in registry) {
- if (registry[key] === Component) {
- name = key
- break
+ // try to infer the name based on reverse resolution
+ const inferFromRegistry = (registry: Record<string, any> | undefined) => {
+ for (const key in registry) {
+ if (registry[key] === Component) {
+ return key
+ }
}
}
+ name =
+ inferFromRegistry(
+ (instance.parent.type as ComponentOptions).components
+ ) || inferFromRegistry(instance.appContext.components)
}
return name ? classify(name) : isRoot ? `App` : `Anonymous`
import { currentRenderingInstance } from '../componentRenderUtils'
-import { currentInstance, Component, FunctionalComponent } from '../component'
+import {
+ currentInstance,
+ Component,
+ FunctionalComponent,
+ ComponentOptions
+} from '../component'
import { Directive } from '../directives'
import { camelize, capitalize, isString } from '@vue/shared'
import { warn } from '../warning'
) {
const instance = currentRenderingInstance || currentInstance
if (instance) {
- let camelized, capitalized
- const registry = instance[type]
- let res =
- registry[name] ||
- registry[(camelized = camelize(name))] ||
- registry[(capitalized = capitalize(camelized))]
- if (!res && type === COMPONENTS) {
- const self = instance.type
- const selfName = (self as FunctionalComponent).displayName || self.name
+ const Component = instance.type
+
+ // self name has highest priority
+ if (type === COMPONENTS) {
+ const selfName =
+ (Component as FunctionalComponent).displayName || Component.name
if (
selfName &&
(selfName === name ||
- selfName === camelized ||
- selfName === capitalized)
+ selfName === camelize(name) ||
+ selfName === capitalize(camelize(name)))
) {
- res = self
+ return Component
}
}
+
+ const res =
+ // local registration
+ resolve((Component as ComponentOptions)[type], name) ||
+ // global registration
+ resolve(instance.appContext[type], name)
if (__DEV__ && warnMissing && !res) {
warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`)
}
)
}
}
+
+function resolve(registry: Record<string, any> | undefined, name: string) {
+ return (
+ registry &&
+ (registry[name] ||
+ registry[camelize(name)] ||
+ registry[capitalize(camelize(name))])
+ )
+}