fix(build): fix component resolution when disabling options API

fix #1688
This commit is contained in:
Evan You 2020-07-23 14:33:15 -04:00
parent ba17c871d8
commit a75b8a268f
3 changed files with 44 additions and 47 deletions

View File

@ -24,7 +24,7 @@ import { Slots, initSlots, InternalSlots } from './componentSlots'
import { warn } from './warning' import { warn } from './warning'
import { ErrorCodes, callWithErrorHandling } from './errorHandling' import { ErrorCodes, callWithErrorHandling } from './errorHandling'
import { AppContext, createAppContext, AppConfig } from './apiCreateApp' import { AppContext, createAppContext, AppConfig } from './apiCreateApp'
import { Directive, validateDirectiveName } from './directives' import { validateDirectiveName } from './directives'
import { applyOptions, ComponentOptions } from './componentOptions' import { applyOptions, ComponentOptions } from './componentOptions'
import { import {
EmitsOptions, EmitsOptions,
@ -223,17 +223,6 @@ export interface ComponentInternalInstance {
*/ */
renderCache: (Function | VNode)[] 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 --------------------------------- // the rest are only for stateful components ---------------------------------
// main proxy that serves as the public instance (`this`) // main proxy that serves as the public instance (`this`)
@ -354,15 +343,17 @@ export function createComponentInstance(
parent: ComponentInternalInstance | null, parent: ComponentInternalInstance | null,
suspense: SuspenseBoundary | null suspense: SuspenseBoundary | null
) { ) {
const type = vnode.type as Component
// inherit parent app context - or - if root, adopt from root vnode // inherit parent app context - or - if root, adopt from root vnode
const appContext = const appContext =
(parent ? parent.appContext : vnode.appContext) || emptyAppContext (parent ? parent.appContext : vnode.appContext) || emptyAppContext
const instance: ComponentInternalInstance = { const instance: ComponentInternalInstance = {
uid: uid++, uid: uid++,
vnode, vnode,
type,
parent, parent,
appContext, appContext,
type: vnode.type as Component,
root: null!, // to be immediately set root: null!, // to be immediately set
next: null, next: null,
subTree: null!, // will be set synchronously right after creation subTree: null!, // will be set synchronously right after creation
@ -385,10 +376,6 @@ export function createComponentInstance(
setupState: EMPTY_OBJ, setupState: EMPTY_OBJ,
setupContext: null, setupContext: null,
// per-instance asset storage (mutable during options resolution)
components: Object.create(appContext.components),
directives: Object.create(appContext.directives),
// suspense related // suspense related
suspense, suspense,
asyncDep: null, asyncDep: null,
@ -727,14 +714,18 @@ export function formatComponentName(
} }
if (!name && instance && instance.parent) { if (!name && instance && instance.parent) {
// try to infer the name based on local resolution // try to infer the name based on reverse resolution
const registry = instance.parent.components const inferFromRegistry = (registry: Record<string, any> | undefined) => {
for (const key in registry) { for (const key in registry) {
if (registry[key] === Component) { if (registry[key] === Component) {
name = key return key
break }
} }
} }
name =
inferFromRegistry(
(instance.parent.type as ComponentOptions).components
) || inferFromRegistry(instance.appContext.components)
} }
return name ? classify(name) : isRoot ? `App` : `Anonymous` return name ? classify(name) : isRoot ? `App` : `Anonymous`

View File

@ -381,9 +381,6 @@ export function applyOptions(
watch: watchOptions, watch: watchOptions,
provide: provideOptions, provide: provideOptions,
inject: injectOptions, inject: injectOptions,
// assets
components,
directives,
// lifecycle // lifecycle
beforeMount, beforeMount,
mounted, mounted,
@ -570,14 +567,6 @@ export function applyOptions(
} }
} }
// asset options
if (components) {
extend(instance.components, components)
}
if (directives) {
extend(instance.directives, directives)
}
// lifecycle options // lifecycle options
if (!asMixin) { if (!asMixin) {
callSyncHook('created', options, publicThis, globalMixins) callSyncHook('created', options, publicThis, globalMixins)

View File

@ -1,5 +1,10 @@
import { currentRenderingInstance } from '../componentRenderUtils' import { currentRenderingInstance } from '../componentRenderUtils'
import { currentInstance, Component, FunctionalComponent } from '../component' import {
currentInstance,
Component,
FunctionalComponent,
ComponentOptions
} from '../component'
import { Directive } from '../directives' import { Directive } from '../directives'
import { camelize, capitalize, isString } from '@vue/shared' import { camelize, capitalize, isString } from '@vue/shared'
import { warn } from '../warning' import { warn } from '../warning'
@ -58,24 +63,27 @@ function resolveAsset(
) { ) {
const instance = currentRenderingInstance || currentInstance const instance = currentRenderingInstance || currentInstance
if (instance) { if (instance) {
let camelized, capitalized const Component = instance.type
const registry = instance[type]
let res = // self name has highest priority
registry[name] || if (type === COMPONENTS) {
registry[(camelized = camelize(name))] || const selfName =
registry[(capitalized = capitalize(camelized))] (Component as FunctionalComponent).displayName || Component.name
if (!res && type === COMPONENTS) {
const self = instance.type
const selfName = (self as FunctionalComponent).displayName || self.name
if ( if (
selfName && selfName &&
(selfName === name || (selfName === name ||
selfName === camelized || selfName === camelize(name) ||
selfName === capitalized) 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) { if (__DEV__ && warnMissing && !res) {
warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`) warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`)
} }
@ -87,3 +95,12 @@ function resolveAsset(
) )
} }
} }
function resolve(registry: Record<string, any> | undefined, name: string) {
return (
registry &&
(registry[name] ||
registry[camelize(name)] ||
registry[capitalize(camelize(name))])
)
}