Skip to content

Commit ccc428c

Browse files
committed
perf(language-core): simplify intrinsic element virtual code
1 parent a402c27 commit ccc428c

File tree

14 files changed

+333
-281
lines changed

14 files changed

+333
-281
lines changed

packages/language-core/lib/codegen/script/component.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function* generateScriptSetupOptions(
7575
yield `${ctx.helperTypes.WithDefaults.name}<`;
7676
}
7777
yield `${ctx.helperTypes.TypePropsToOption.name}<`;
78-
yield `typeof __VLS_componentProps>`;
78+
yield `__VLS_PublicProps>`;
7979
if (scriptSetupRanges.props.withDefaults?.arg) {
8080
yield `, typeof __VLS_withDefaultsArg>`;
8181
}

packages/language-core/lib/codegen/script/globalTypes.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ declare global {
7979
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
8080
: T extends (...args: any) => any ? T
8181
: (_: {}${vueCompilerOptions.strictTemplates ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: {}${vueCompilerOptions.strictTemplates ? '' : ' & Record<string, unknown>'} } };
82-
function __VLS_elementAsFunctionalComponent<T>(t: T): (_: T${vueCompilerOptions.strictTemplates ? '' : ' & Record<string, unknown>'}, ctx?: any) => { __ctx?: { attrs?: any, expose?: any, slots?: any, emit?: any, props?: T${vueCompilerOptions.strictTemplates ? '' : ' & Record<string, unknown>'} } };
82+
function __VLS_elementAsFunction<T>(tag: T, endTag?: T): (_: T${vueCompilerOptions.strictTemplates ? '' : ' & Record<string, unknown>'}) => void;
8383
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): Parameters<T>['length'] extends 2 ? [any] : [];
8484
function __VLS_pickEvent<E1, E2>(emitEvent: E1, propEvent: E2): __VLS_FillingEventArg<
8585
__VLS_PickNotAny<

packages/language-core/lib/codegen/script/scriptSetup.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function* generateScriptSetup(
4747
+ ` __VLS_setup = (async () => {${newLine}`;
4848
yield* generateSetupFunction(options, ctx, scriptSetup, scriptSetupRanges, undefined, definePropMirrors);
4949
yield ` return {} as {${newLine}`
50-
+ ` props: ${ctx.helperTypes.Prettify.name}<typeof __VLS_functionalComponentProps & typeof __VLS_componentProps> & typeof __VLS_publicProps,${newLine}`
50+
+ ` props: ${ctx.helperTypes.Prettify.name}<typeof __VLS_functionalComponentProps & __VLS_PublicProps> & __VLS_BuiltInPublicProps,${newLine}`
5151
+ ` expose(exposed: import('${options.vueCompilerOptions.lib}').ShallowUnwrapRef<${scriptSetupRanges.expose.define ? 'typeof __VLS_exposed' : '{}'}>): void,${newLine}`
5252
+ ` attrs: any,${newLine}`
5353
+ ` slots: ReturnType<typeof __VLS_template>,${newLine}`
@@ -246,14 +246,14 @@ function* generateComponentProps(
246246
}
247247
yield `})${endOfLine}`;
248248
yield `let __VLS_functionalComponentProps!: `;
249-
yield `${ctx.helperTypes.OmitKeepDiscriminatedUnion.name}<InstanceType<typeof __VLS_fnComponent>['$props'], keyof typeof __VLS_publicProps>`;
249+
yield `${ctx.helperTypes.OmitKeepDiscriminatedUnion.name}<InstanceType<typeof __VLS_fnComponent>['$props'], keyof __VLS_BuiltInPublicProps>`;
250250
yield endOfLine;
251251
}
252252
else {
253253
yield `let __VLS_functionalComponentProps!: {}${endOfLine}`;
254254
}
255255

256-
yield `let __VLS_publicProps!:${newLine}`
256+
yield `type __VLS_BuiltInPublicProps =${newLine}`
257257
+ ` import('${options.vueCompilerOptions.lib}').VNodeProps${newLine}`
258258
+ ` & import('${options.vueCompilerOptions.lib}').AllowedComponentProps${newLine}`
259259
+ ` & import('${options.vueCompilerOptions.lib}').ComponentCustomProps${endOfLine}`;
@@ -276,7 +276,7 @@ function* generateComponentProps(
276276
yield `}${endOfLine}`;
277277
}
278278

279-
yield `let __VLS_componentProps!: `;
279+
yield `type __VLS_PublicProps = `;
280280
if (scriptSetupRanges.slots.define && options.vueCompilerOptions.jsxSlots) {
281281
if (ctx.generatedPropsType) {
282282
yield ` & `;

packages/language-core/lib/codegen/template/context.ts

-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ export function createTemplateCodegenContext() {
167167
generateAutoImportCompletion: function* (): Generator<Code> {
168168
const all = [...accessGlobalVariables.entries()];
169169
if (!all.some(([_, offsets]) => offsets.size)) {
170-
yield `// no auto imports${endOfLine}`;
171170
return;
172171
}
173172
yield `// @ts-ignore${newLine}`; // #2304

packages/language-core/lib/codegen/template/element.ts

+157-53
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import { camelize, capitalize } from '@vue/shared';
33
import type { Code, VueCodeInformation } from '../../types';
4+
import { hyphenateTag } from '../../utils/shared';
45
import { collectVars, createTsAst, endOfLine, newLine, variableNameRegex, wrapWith } from '../common';
56
import { generateCamelized } from './camelized';
67
import type { TemplateCodegenContext } from './context';
@@ -11,16 +12,15 @@ import { generateElementProps } from './elementProps';
1112
import type { TemplateCodegenOptions } from './index';
1213
import { generateInterpolation } from './interpolation';
1314
import { generatePropertyAccess } from './propertyAccess';
14-
import { generateStringLiteralKey } from './stringLiteralKey';
1515
import { generateTemplateChild } from './templateChild';
1616

1717
const colonReg = /:/g;
1818

19-
export function* generateElement(
19+
export function* generateComponent(
2020
options: TemplateCodegenOptions,
2121
ctx: TemplateCodegenContext,
2222
node: CompilerDOM.ElementNode,
23-
currentElement: CompilerDOM.ElementNode | undefined,
23+
currentComponent: CompilerDOM.ElementNode | undefined,
2424
componentCtxVar: string | undefined,
2525
): Generator<Code> {
2626
const startTagOffset = node.loc.start.offset + options.template.content.substring(node.loc.start.offset).indexOf(node.tag);
@@ -29,8 +29,6 @@ export function* generateElement(
2929
const var_functionalComponent = ctx.getInternalVariable();
3030
const var_componentInstance = ctx.getInternalVariable();
3131
const var_componentEvents = ctx.getInternalVariable();
32-
const isIntrinsicElement = node.tagType === CompilerDOM.ElementTypes.ELEMENT
33-
|| node.tagType === CompilerDOM.ElementTypes.TEMPLATE;
3432
const isComponentTag = node.tag.toLowerCase() === 'component';
3533

3634
let endTagOffset = !node.isSelfClosing && options.template.lang === 'html' ? node.loc.start.offset + node.loc.source.lastIndexOf(node.tag) : undefined;
@@ -69,16 +67,7 @@ export function* generateElement(
6967
};
7068
}
7169

72-
if (isIntrinsicElement) {
73-
yield `const ${var_originalComponent} = __VLS_intrinsicElements[`;
74-
yield* generateStringLiteralKey(
75-
tag,
76-
startTagOffset,
77-
ctx.codeFeatures.verification,
78-
);
79-
yield `]${endOfLine}`;
80-
}
81-
else if (dynamicTagInfo) {
70+
if (dynamicTagInfo) {
8271
yield `const ${var_originalComponent} = `;
8372
yield* generateInterpolation(
8473
options,
@@ -113,20 +102,15 @@ export function* generateElement(
113102
yield `const ${var_originalComponent} = {} as any${endOfLine}`;
114103
}
115104

116-
if (isIntrinsicElement) {
117-
yield `const ${var_functionalComponent} = __VLS_elementAsFunctionalComponent(${var_originalComponent})${endOfLine}`;
118-
}
119-
else {
120-
yield `const ${var_functionalComponent} = __VLS_asFunctionalComponent(${var_originalComponent}, new ${var_originalComponent}({`;
121-
yield* generateElementProps(options, ctx, node, props, false);
122-
yield `}))${endOfLine}`;
123-
}
105+
yield `const ${var_functionalComponent} = __VLS_asFunctionalComponent(${var_originalComponent}, new ${var_originalComponent}({`;
106+
yield* generateElementProps(options, ctx, node, props, false);
107+
yield `}))${endOfLine}`;
124108

125109
if (
126110
!dynamicTagInfo
127-
&& !isIntrinsicElement
128111
&& !isComponentTag
129112
) {
113+
// hover support
130114
for (const offset of tagOffsets) {
131115
yield `({} as { ${getCanonicalComponentName(tag)}: typeof ${var_originalComponent} }).`;
132116
yield* generateCanonicalComponentName(
@@ -136,6 +120,45 @@ export function* generateElement(
136120
);
137121
yield endOfLine;
138122
}
123+
const camelizedTag = camelize(node.tag);
124+
if (variableNameRegex.test(camelizedTag)) {
125+
// renaming / find references support
126+
for (const tagOffset of tagOffsets) {
127+
for (const shouldCapitalize of (node.tag[0] === node.tag[0].toUpperCase() ? [false] : [true, false])) {
128+
const expectName = shouldCapitalize ? capitalize(camelizedTag) : camelizedTag;
129+
yield `__VLS_components.`;
130+
yield* generateCamelized(
131+
shouldCapitalize ? capitalize(node.tag) : node.tag,
132+
tagOffset,
133+
{
134+
navigation: {
135+
resolveRenameNewName: node.tag !== expectName ? camelizeComponentName : undefined,
136+
resolveRenameEditText: getTagRenameApply(node.tag),
137+
},
138+
} as VueCodeInformation,
139+
);
140+
yield `;`;
141+
}
142+
}
143+
yield `${newLine}`;
144+
// auto import support
145+
yield `// @ts-ignore${newLine}`; // #2304
146+
yield `[`;
147+
for (const tagOffset of tagOffsets) {
148+
yield* generateCamelized(
149+
capitalize(node.tag),
150+
tagOffset,
151+
{
152+
completion: {
153+
isAdditional: true,
154+
onlyImport: true,
155+
},
156+
} as VueCodeInformation,
157+
);
158+
yield `,`;
159+
}
160+
yield `]${endOfLine}`;
161+
}
139162
}
140163

141164
if (options.vueCompilerOptions.strictTemplates) {
@@ -169,13 +192,89 @@ export function* generateElement(
169192
yield `)${endOfLine}`;
170193
}
171194

172-
if (node.tagType !== CompilerDOM.ElementTypes.TEMPLATE) {
173-
defineComponentCtxVar = ctx.getInternalVariable();
174-
componentCtxVar = defineComponentCtxVar;
175-
currentElement = node;
195+
defineComponentCtxVar = ctx.getInternalVariable();
196+
componentCtxVar = defineComponentCtxVar;
197+
currentComponent = node;
198+
199+
for (const failedExp of propsFailedExps) {
200+
yield* generateInterpolation(
201+
options,
202+
ctx,
203+
failedExp.loc.source,
204+
failedExp.loc,
205+
failedExp.loc.start.offset,
206+
ctx.codeFeatures.all,
207+
'(',
208+
')',
209+
);
210+
yield endOfLine;
211+
}
212+
213+
yield* generateVScope(options, ctx, node, props);
214+
215+
if (componentCtxVar) {
216+
ctx.usedComponentCtxVars.add(componentCtxVar);
217+
yield* generateElementEvents(options, ctx, node, var_functionalComponent, var_componentInstance, var_componentEvents, () => usedComponentEventsVar = true);
218+
}
219+
220+
const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode;
221+
if (slotDir && componentCtxVar) {
222+
yield* generateComponentSlot(options, ctx, node, slotDir, currentComponent, componentCtxVar);
223+
}
224+
else {
225+
yield* generateElementChildren(options, ctx, node, currentComponent, componentCtxVar);
226+
}
227+
228+
if (defineComponentCtxVar && ctx.usedComponentCtxVars.has(defineComponentCtxVar)) {
229+
yield `const ${componentCtxVar} = __VLS_pickFunctionalComponentCtx(${var_originalComponent}, ${var_componentInstance})!${endOfLine}`;
230+
}
231+
if (usedComponentEventsVar) {
232+
yield `let ${var_componentEvents}!: __VLS_NormalizeEmits<typeof ${componentCtxVar}.emit>${endOfLine}`;
233+
}
234+
}
235+
236+
export function* generateElement(
237+
options: TemplateCodegenOptions,
238+
ctx: TemplateCodegenContext,
239+
node: CompilerDOM.ElementNode,
240+
currentComponent: CompilerDOM.ElementNode | undefined,
241+
componentCtxVar: string | undefined,
242+
): Generator<Code> {
243+
const startTagOffset = node.loc.start.offset + options.template.content.substring(node.loc.start.offset).indexOf(node.tag);
244+
const endTagOffset = !node.isSelfClosing && options.template.lang === 'html'
245+
? node.loc.start.offset + node.loc.source.lastIndexOf(node.tag)
246+
: undefined;
247+
const propsFailedExps: CompilerDOM.SimpleExpressionNode[] = [];
248+
249+
yield `__VLS_elementAsFunction(__VLS_intrinsicElements`;
250+
yield* generatePropertyAccess(
251+
options,
252+
ctx,
253+
node.tag,
254+
startTagOffset,
255+
ctx.codeFeatures.withoutHighlightAndCompletion,
256+
);
257+
if (endTagOffset !== undefined) {
258+
yield `, __VLS_intrinsicElements`;
259+
yield* generatePropertyAccess(
260+
options,
261+
ctx,
262+
node.tag,
263+
endTagOffset,
264+
ctx.codeFeatures.withoutHighlightAndCompletion,
265+
);
176266
}
267+
yield `)(`;
268+
yield* wrapWith(
269+
startTagOffset,
270+
startTagOffset + node.tag.length,
271+
ctx.codeFeatures.verification,
272+
`{`,
273+
...generateElementProps(options, ctx, node, node.props, true, propsFailedExps),
274+
`}`,
275+
);
276+
yield `)${endOfLine}`;
177277

178-
//#region fix #1775
179278
for (const failedExp of propsFailedExps) {
180279
yield* generateInterpolation(
181280
options,
@@ -190,6 +289,23 @@ export function* generateElement(
190289
yield endOfLine;
191290
}
192291

292+
yield* generateVScope(options, ctx, node, node.props);
293+
294+
const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode;
295+
if (slotDir && componentCtxVar) {
296+
yield* generateComponentSlot(options, ctx, node, slotDir, currentComponent, componentCtxVar);
297+
}
298+
else {
299+
yield* generateElementChildren(options, ctx, node, currentComponent, componentCtxVar);
300+
}
301+
}
302+
303+
function* generateVScope(
304+
options: TemplateCodegenOptions,
305+
ctx: TemplateCodegenContext,
306+
node: CompilerDOM.ElementNode,
307+
props: (CompilerDOM.AttributeNode | CompilerDOM.DirectiveNode)[],
308+
): Generator<Code> {
193309
const vScope = props.find(prop => prop.type === CompilerDOM.NodeTypes.DIRECTIVE && (prop.name === 'scope' || prop.name === 'data'));
194310
let inScope = false;
195311
let originalConditionsNum = ctx.blockConditions.length;
@@ -217,31 +333,11 @@ export function* generateElement(
217333
if (options.shouldGenerateScopedClasses) {
218334
yield* generateReferencesForScopedCssClasses(ctx, node);
219335
}
220-
if (componentCtxVar) {
221-
ctx.usedComponentCtxVars.add(componentCtxVar);
222-
yield* generateElementEvents(options, ctx, node, var_functionalComponent, var_componentInstance, var_componentEvents, () => usedComponentEventsVar = true);
223-
}
224336

225337
if (inScope) {
226338
yield `}${newLine}`;
227339
ctx.blockConditions.length = originalConditionsNum;
228340
}
229-
//#endregion
230-
231-
const slotDir = node.props.find(p => p.type === CompilerDOM.NodeTypes.DIRECTIVE && p.name === 'slot') as CompilerDOM.DirectiveNode;
232-
if (slotDir && componentCtxVar) {
233-
yield* generateComponentSlot(options, ctx, node, slotDir, currentElement, componentCtxVar);
234-
}
235-
else {
236-
yield* generateElementChildren(options, ctx, node, currentElement, componentCtxVar);
237-
}
238-
239-
if (defineComponentCtxVar && ctx.usedComponentCtxVars.has(defineComponentCtxVar)) {
240-
yield `const ${componentCtxVar} = __VLS_pickFunctionalComponentCtx(${var_originalComponent}, ${var_componentInstance})!${endOfLine}`;
241-
}
242-
if (usedComponentEventsVar) {
243-
yield `let ${var_componentEvents}!: __VLS_NormalizeEmits<typeof ${componentCtxVar}.emit>${endOfLine}`;
244-
}
245341
}
246342

247343
export function getCanonicalComponentName(tagText: string) {
@@ -282,13 +378,13 @@ function* generateComponentSlot(
282378
ctx: TemplateCodegenContext,
283379
node: CompilerDOM.ElementNode,
284380
slotDir: CompilerDOM.DirectiveNode,
285-
currentElement: CompilerDOM.ElementNode | undefined,
381+
currentComponent: CompilerDOM.ElementNode | undefined,
286382
componentCtxVar: string,
287383
): Generator<Code> {
288384
yield `{${newLine}`;
289385
ctx.usedComponentCtxVars.add(componentCtxVar);
290-
if (currentElement) {
291-
ctx.hasSlotElements.add(currentElement);
386+
if (currentComponent) {
387+
ctx.hasSlotElements.add(currentComponent);
292388
}
293389
const slotBlockVars: string[] = [];
294390
let hasProps = false;
@@ -363,7 +459,7 @@ function* generateComponentSlot(
363459

364460
let prev: CompilerDOM.TemplateChildNode | undefined;
365461
for (const childNode of node.children) {
366-
yield* generateTemplateChild(options, ctx, childNode, currentElement, prev, componentCtxVar);
462+
yield* generateTemplateChild(options, ctx, childNode, currentComponent, prev, componentCtxVar);
367463
prev = childNode;
368464
}
369465

@@ -464,3 +560,11 @@ function* generateReferencesForScopedCssClasses(
464560
}
465561
}
466562
}
563+
564+
function camelizeComponentName(newName: string) {
565+
return camelize('-' + newName);
566+
}
567+
568+
function getTagRenameApply(oldName: string) {
569+
return oldName === hyphenateTag(oldName) ? hyphenateTag : undefined;
570+
}

0 commit comments

Comments
 (0)