mirror of https://github.com/vuejs/core.git
feat(compiler-vapor): resolve implicitly self-referencing component (#13400)
This commit is contained in:
parent
08f9c1d9f6
commit
978c47f751
|
@ -17,6 +17,7 @@ export {
|
||||||
createTransformContext,
|
createTransformContext,
|
||||||
traverseNode,
|
traverseNode,
|
||||||
createStructuralDirectiveTransform,
|
createStructuralDirectiveTransform,
|
||||||
|
getSelfName,
|
||||||
type NodeTransform,
|
type NodeTransform,
|
||||||
type StructuralDirectiveTransform,
|
type StructuralDirectiveTransform,
|
||||||
type DirectiveTransform,
|
type DirectiveTransform,
|
||||||
|
|
|
@ -123,6 +123,11 @@ export interface TransformContext
|
||||||
filters?: Set<string>
|
filters?: Set<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSelfName(filename: string): string | null {
|
||||||
|
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
|
||||||
|
return nameMatch ? capitalize(camelize(nameMatch[1])) : null
|
||||||
|
}
|
||||||
|
|
||||||
export function createTransformContext(
|
export function createTransformContext(
|
||||||
root: RootNode,
|
root: RootNode,
|
||||||
{
|
{
|
||||||
|
@ -150,11 +155,10 @@ export function createTransformContext(
|
||||||
compatConfig,
|
compatConfig,
|
||||||
}: TransformOptions,
|
}: TransformOptions,
|
||||||
): TransformContext {
|
): TransformContext {
|
||||||
const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/)
|
|
||||||
const context: TransformContext = {
|
const context: TransformContext = {
|
||||||
// options
|
// options
|
||||||
filename,
|
filename,
|
||||||
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
|
selfName: getSelfName(filename),
|
||||||
prefixIdentifiers,
|
prefixIdentifiers,
|
||||||
hoistStatic,
|
hoistStatic,
|
||||||
hmr,
|
hmr,
|
||||||
|
|
|
@ -77,6 +77,16 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: element transform > component > resolve implicitly self-referencing component 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
||||||
|
|
||||||
|
export function render(_ctx) {
|
||||||
|
const _component_Example__self = _resolveComponent("Example", true)
|
||||||
|
const n0 = _createComponentWithFallback(_component_Example__self, null, null, true)
|
||||||
|
return n0
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`compiler: element transform > component > resolve namespaced component from props bindings (inline) 1`] = `
|
exports[`compiler: element transform > component > resolve namespaced component from props bindings (inline) 1`] = `
|
||||||
"
|
"
|
||||||
const n0 = _createComponent(Foo.Example, null, null, true)
|
const n0 = _createComponent(Foo.Example, null, null, true)
|
||||||
|
|
|
@ -39,11 +39,12 @@ describe('compiler: element transform', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test.todo('resolve implicitly self-referencing component', () => {
|
test('resolve implicitly self-referencing component', () => {
|
||||||
const { code, helpers } = compileWithElementTransform(`<Example/>`, {
|
const { code, helpers } = compileWithElementTransform(`<Example/>`, {
|
||||||
filename: `/foo/bar/Example.vue?vue&type=template`,
|
filename: `/foo/bar/Example.vue?vue&type=template`,
|
||||||
})
|
})
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(code).toContain('_resolveComponent("Example", true)')
|
||||||
expect(helpers).toContain('resolveComponent')
|
expect(helpers).toContain('resolveComponent')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,21 @@ export function genBlockContent(
|
||||||
const resetBlock = context.enterBlock(block)
|
const resetBlock = context.enterBlock(block)
|
||||||
|
|
||||||
if (root) {
|
if (root) {
|
||||||
genResolveAssets('component', 'resolveComponent')
|
for (let name of context.ir.component) {
|
||||||
|
const id = toValidAssetId(name, 'component')
|
||||||
|
const maybeSelfReference = name.endsWith('__self')
|
||||||
|
if (maybeSelfReference) name = name.slice(0, -6)
|
||||||
|
push(
|
||||||
|
NEWLINE,
|
||||||
|
`const ${id} = `,
|
||||||
|
...genCall(
|
||||||
|
context.helper('resolveComponent'),
|
||||||
|
JSON.stringify(name),
|
||||||
|
// pass additional `maybeSelfReference` flag
|
||||||
|
maybeSelfReference ? 'true' : undefined,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
genResolveAssets('directive', 'resolveDirective')
|
genResolveAssets('directive', 'resolveDirective')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
type TemplateChildNode,
|
type TemplateChildNode,
|
||||||
defaultOnError,
|
defaultOnError,
|
||||||
defaultOnWarn,
|
defaultOnWarn,
|
||||||
|
getSelfName,
|
||||||
isVSlot,
|
isVSlot,
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
|
import { EMPTY_OBJ, NOOP, extend, isArray, isString } from '@vue/shared'
|
||||||
|
@ -61,6 +62,7 @@ export type StructuralDirectiveTransform = (
|
||||||
export type TransformOptions = HackOptions<BaseTransformOptions>
|
export type TransformOptions = HackOptions<BaseTransformOptions>
|
||||||
|
|
||||||
export class TransformContext<T extends AllNode = AllNode> {
|
export class TransformContext<T extends AllNode = AllNode> {
|
||||||
|
selfName: string | null = null
|
||||||
parent: TransformContext<RootNode | ElementNode> | null = null
|
parent: TransformContext<RootNode | ElementNode> | null = null
|
||||||
root: TransformContext<RootNode>
|
root: TransformContext<RootNode>
|
||||||
index: number = 0
|
index: number = 0
|
||||||
|
@ -92,6 +94,7 @@ export class TransformContext<T extends AllNode = AllNode> {
|
||||||
) {
|
) {
|
||||||
this.options = extend({}, defaultOptions, options)
|
this.options = extend({}, defaultOptions, options)
|
||||||
this.root = this as TransformContext<RootNode>
|
this.root = this as TransformContext<RootNode>
|
||||||
|
if (options.filename) this.selfName = getSelfName(options.filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
enterBlock(ir: BlockIRNode, isVFor: boolean = false): () => void {
|
enterBlock(ir: BlockIRNode, isVFor: boolean = false): () => void {
|
||||||
|
|
|
@ -119,6 +119,13 @@ function transformComponentElement(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asset) {
|
if (asset) {
|
||||||
|
// self referencing component (inferred from filename)
|
||||||
|
if (context.selfName && capitalize(camelize(tag)) === context.selfName) {
|
||||||
|
// generators/block.ts has special check for __self postfix when generating
|
||||||
|
// component imports, which will pass additional `maybeSelfReference` flag
|
||||||
|
// to `resolveComponent`.
|
||||||
|
tag += `__self`
|
||||||
|
}
|
||||||
context.component.add(tag)
|
context.component.add(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue