Skip to content

Commit 978c47f

Browse files
authored
feat(compiler-vapor): resolve implicitly self-referencing component (#13400)
1 parent 08f9c1d commit 978c47f

File tree

7 files changed

+44
-4
lines changed

7 files changed

+44
-4
lines changed

packages/compiler-core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export {
1717
createTransformContext,
1818
traverseNode,
1919
createStructuralDirectiveTransform,
20+
getSelfName,
2021
type NodeTransform,
2122
type StructuralDirectiveTransform,
2223
type DirectiveTransform,

packages/compiler-core/src/transform.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ export interface TransformContext
123123
filters?: Set<string>
124124
}
125125

126+
export function getSelfName(filename: string): string | null {
127+
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
128+
return nameMatch ? capitalize(camelize(nameMatch[1])) : null
129+
}
130+
126131
export function createTransformContext(
127132
root: RootNode,
128133
{
@@ -150,11 +155,10 @@ export function createTransformContext(
150155
compatConfig,
151156
}: TransformOptions,
152157
): TransformContext {
153-
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
154158
const context: TransformContext = {
155159
// options
156160
filename,
157-
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
161+
selfName: getSelfName(filename),
158162
prefixIdentifiers,
159163
hoistStatic,
160164
hmr,

packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
7777
}"
7878
`;
7979

80+
exports[`compiler: element transform > component > resolve implicitly self-referencing component 1`] = `
81+
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
82+
83+
export function render(_ctx) {
84+
const _component_Example__self = _resolveComponent("Example", true)
85+
const n0 = _createComponentWithFallback(_component_Example__self, null, null, true)
86+
return n0
87+
}"
88+
`;
89+
8090
exports[`compiler: element transform > component > resolve namespaced component from props bindings (inline) 1`] = `
8191
"
8292
const n0 = _createComponent(Foo.Example, null, null, true)

packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ describe('compiler: element transform', () => {
3939
})
4040
})
4141

42-
test.todo('resolve implicitly self-referencing component', () => {
42+
test('resolve implicitly self-referencing component', () => {
4343
const { code, helpers } = compileWithElementTransform(`<Example/>`, {
4444
filename: `/foo/bar/Example.vue?vue&type=template`,
4545
})
4646
expect(code).toMatchSnapshot()
47+
expect(code).toContain('_resolveComponent("Example", true)')
4748
expect(helpers).toContain('resolveComponent')
4849
})
4950

packages/compiler-vapor/src/generators/block.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,21 @@ export function genBlockContent(
4444
const resetBlock = context.enterBlock(block)
4545

4646
if (root) {
47-
genResolveAssets('component', 'resolveComponent')
47+
for (let name of context.ir.component) {
48+
const id = toValidAssetId(name, 'component')
49+
const maybeSelfReference = name.endsWith('__self')
50+
if (maybeSelfReference) name = name.slice(0, -6)
51+
push(
52+
NEWLINE,
53+
`const ${id} = `,
54+
...genCall(
55+
context.helper('resolveComponent'),
56+
JSON.stringify(name),
57+
// pass additional `maybeSelfReference` flag
58+
maybeSelfReference ? 'true' : undefined,
59+
),
60+
)
61+
}
4862
genResolveAssets('directive', 'resolveDirective')
4963
}
5064

packages/compiler-vapor/src/transform.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
type TemplateChildNode,
1212
defaultOnError,
1313
defaultOnWarn,
14+
getSelfName,
1415
isVSlot,
1516
} from '@vue/compiler-dom'
1617
import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
@@ -61,6 +62,7 @@ export type StructuralDirectiveTransform = (
6162
export type TransformOptions = HackOptions<BaseTransformOptions>
6263

6364
export class TransformContext<T extends AllNode = AllNode> {
65+
selfName: string | null = null
6466
parent: TransformContext<RootNode | ElementNode> | null = null
6567
root: TransformContext<RootNode>
6668
index: number = 0
@@ -92,6 +94,7 @@ export class TransformContext<T extends AllNode = AllNode> {
9294
) {
9395
this.options = extend({}, defaultOptions, options)
9496
this.root = this as TransformContext<RootNode>
97+
if (options.filename) this.selfName = getSelfName(options.filename)
9598
}
9699

97100
enterBlock(ir: BlockIRNode, isVFor: boolean = false): () => void {

packages/compiler-vapor/src/transforms/transformElement.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ function transformComponentElement(
119119
}
120120

121121
if (asset) {
122+
// self referencing component (inferred from filename)
123+
if (context.selfName && capitalize(camelize(tag)) === context.selfName) {
124+
// generators/block.ts has special check for __self postfix when generating
125+
// component imports, which will pass additional `maybeSelfReference` flag
126+
// to `resolveComponent`.
127+
tag += `__self`
128+
}
122129
context.component.add(tag)
123130
}
124131
}

0 commit comments

Comments
 (0)