const _component_Foo = _resolveComponent(\\"Foo\\")
const _component_bar_baz = _resolveComponent(\\"bar-baz\\")
const _component_barbaz = _resolveComponent(\\"barbaz\\")
+ const _component_Qux = _resolveComponent(\\"Qux\\", true)
const _directive_my_dir_0 = _resolveDirective(\\"my_dir_0\\")
const _directive_my_dir_1 = _resolveDirective(\\"my_dir_1\\")
let _temp0, _temp1, _temp2
test('assets + temps', () => {
const root = createRoot({
- components: [`Foo`, `bar-baz`, `barbaz`],
+ components: [`Foo`, `bar-baz`, `barbaz`, `Qux__self`],
directives: [`my_dir_0`, `my_dir_1`],
temps: 3
})
helperNameMap[RESOLVE_COMPONENT]
}("barbaz")\n`
)
+ // implicit self reference from SFC filename
+ expect(code).toMatch(
+ `const _component_Qux = _${
+ helperNameMap[RESOLVE_COMPONENT]
+ }("Qux", true)\n`
+ )
expect(code).toMatch(
`const _directive_my_dir_0 = _${
helperNameMap[RESOLVE_DIRECTIVE]
filename: `/foo/bar/Example.vue?vue&type=template`
})
expect(root.helpers).toContain(RESOLVE_COMPONENT)
- expect(root.components).toContain(`_self`)
+ expect(root.components).toContain(`Example__self`)
})
test('static props', () => {
type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE
)
for (let i = 0; i < assets.length; i++) {
- const id = assets[i]
+ let id = assets[i]
+ // potential component implicit self-reference inferred from SFC filename
+ const maybeSelfReference = id.endsWith('__self')
+ if (maybeSelfReference) {
+ id = id.slice(0, -6)
+ }
push(
- `const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`
+ `const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${
+ maybeSelfReference ? `, true` : ``
+ })`
)
if (i < assets.length - 1) {
newline()
}
// 4. Self referencing component (inferred from filename)
- if (!__BROWSER__ && context.selfName) {
- if (capitalize(camelize(tag)) === context.selfName) {
- context.helper(RESOLVE_COMPONENT)
- context.components.add(`_self`)
- return toValidAssetId(`_self`, `component`)
- }
+ if (
+ !__BROWSER__ &&
+ context.selfName &&
+ capitalize(camelize(tag)) === context.selfName
+ ) {
+ context.helper(RESOLVE_COMPONENT)
+ // codegen.ts has special check for __self postfix when generating
+ // component imports, which will pass additional `maybeSelfReference` flag
+ // to `resolveComponent`.
+ context.components.add(tag + `__self`)
+ return toValidAssetId(tag, `component`)
}
// 5. user component (resolve)
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')
/**
* @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()
function resolveAsset(
type: typeof COMPONENTS,
name: string,
- warnMissing?: boolean
+ warnMissing?: boolean,
+ maybeSelfReference?: boolean
): ConcreteComponent | undefined
// overload 2: directives
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 &&
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(
export const compilerOptions: CompilerOptions = reactive({
mode: 'module',
+ filename: 'Foo.vue',
prefixIdentifiers: false,
optimizeImports: false,
hoistStatic: false,