fix(component): prioritize registered component over implicit self-reference via filename

ref: #2827
This commit is contained in:
Evan You
2021-03-26 10:04:29 -04:00
parent e2469fd014
commit abd129d845
8 changed files with 78 additions and 21 deletions

View File

@@ -65,6 +65,37 @@ describe('resolveAssets', () => {
expect(directive4!).toBe(BarBaz)
})
test('maybeSelfReference', async () => {
let component1: Component | string
let component2: Component | string
let component3: Component | string
const Foo = () => null
const Root = {
name: 'Root',
components: {
Foo,
Root: Foo
},
setup() {
return () => {
component1 = resolveComponent('Root', true)
component2 = resolveComponent('Foo', true)
component3 = resolveComponent('Bar', true)
}
}
}
const app = createApp(Root)
const root = nodeOps.createElement('div')
app.mount(root)
expect(component1!).toBe(Root) // explicit self name reference
expect(component2!).toBe(Foo) // successful resolve take higher priority
expect(component3!).toBe(Root) // fallback when resolve fails
})
describe('warning', () => {
test('used outside render() or setup()', () => {
resolveComponent('foo')

View File

@@ -16,8 +16,11 @@ const DIRECTIVES = 'directives'
/**
* @private
*/
export function resolveComponent(name: string): ConcreteComponent | string {
return resolveAsset(COMPONENTS, name) || name
export function resolveComponent(
name: string,
maybeSelfReference?: boolean
): ConcreteComponent | string {
return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name
}
export const NULL_DYNAMIC_COMPONENT = Symbol()
@@ -48,7 +51,8 @@ export function resolveDirective(name: string): Directive | undefined {
function resolveAsset(
type: typeof COMPONENTS,
name: string,
warnMissing?: boolean
warnMissing?: boolean,
maybeSelfReference?: boolean
): ConcreteComponent | undefined
// overload 2: directives
function resolveAsset(
@@ -59,20 +63,15 @@ function resolveAsset(
function resolveAsset(
type: typeof COMPONENTS | typeof DIRECTIVES,
name: string,
warnMissing = true
warnMissing = true,
maybeSelfReference = false
) {
const instance = currentRenderingInstance || currentInstance
if (instance) {
const Component = instance.type
// self name has highest priority
// explicit self name has highest priority
if (type === COMPONENTS) {
// special self referencing call generated by compiler
// inferred from SFC filename
if (name === `_self`) {
return Component
}
const selfName = getComponentName(Component)
if (
selfName &&
@@ -90,9 +89,16 @@ function resolveAsset(
resolve(instance[type] || (Component as ComponentOptions)[type], name) ||
// global registration
resolve(instance.appContext[type], name)
if (!res && maybeSelfReference) {
// fallback to implicit self-reference
return Component
}
if (__DEV__ && warnMissing && !res) {
warn(`Failed to resolve ${type.slice(0, -1)}: ${name}`)
}
return res
} else if (__DEV__) {
warn(