Skip to content

Commit 3dd0a24

Browse files
committed
fix(language-core): use a global WeakMap variable to cache inline ts asts
1 parent d1b55a4 commit 3dd0a24

File tree

9 files changed

+27
-17
lines changed

9 files changed

+27
-17
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as CompilerDOM from '@vue/compiler-dom';
22
import type { Code, VueCodeInformation } from '../../types';
3+
import { templateInlineTsAsts } from '../../virtualFile/computedSfc';
34
import { codeFeatures } from '../codeFeatures';
45
import type { InlayHintInfo } from '../inlayHints';
56
import { endOfLine, newLine } from '../utils';
@@ -107,7 +108,10 @@ const commentDirectiveRegex = /^<!--\s*@vue-(?<name>[-\w]+)\b(?<content>[\s\S]*)
107108
* an error/diagnostic was encountered for a region of code covered by a `@vue-expect-error` directive,
108109
* and additionally how we use that to determine whether to propagate diagnostics back upward.
109110
*/
110-
export function createTemplateCodegenContext(options: Pick<TemplateCodegenOptions, 'scriptSetupBindingNames'>) {
111+
export function createTemplateCodegenContext(
112+
options: Pick<TemplateCodegenOptions, 'scriptSetupBindingNames'>,
113+
templateAst?: CompilerDOM.RootNode,
114+
) {
111115
let variableId = 0;
112116

113117
function resolveCodeFeatures(features: VueCodeInformation) {
@@ -194,6 +198,7 @@ export function createTemplateCodegenContext(options: Pick<TemplateCodegenOption
194198
},
195199
}),
196200
resolveCodeFeatures,
201+
inlineTsAsts: templateAst && templateInlineTsAsts.get(templateAst),
197202
inVFor: false,
198203
slots,
199204
dynamicSlots,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export function* generateEventExpression(
117117
let suffix = `)`;
118118
let isFirstMapping = true;
119119

120-
const ast = createTsAst(options.ts, options.template.ast, prop.exp.content);
120+
const ast = createTsAst(options.ts, ctx.inlineTsAsts, prop.exp.content);
121121
const isCompound = isCompoundExpression(options.ts, ast);
122122

123123
if (isCompound) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export interface TemplateCodegenOptions {
2525
}
2626

2727
export function* generateTemplate(options: TemplateCodegenOptions): Generator<Code, TemplateCodegenContext> {
28-
const ctx = createTemplateCodegenContext(options);
28+
const ctx = createTemplateCodegenContext(options, options.template.ast);
2929

3030
if (options.slotsAssignName) {
3131
ctx.addLocalVariable(options.slotsAssignName);

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { isGloballyAllowed, makeMap } from '@vue/shared';
22
import type * as ts from 'typescript';
3-
import type { Code, Sfc, VueCodeInformation } from '../../types';
3+
import type { Code, VueCodeInformation } from '../../types';
44
import { getNodeText, getStartEnd } from '../../utils/shared';
55
import type { ScriptCodegenOptions } from '../script';
66
import { collectVars, createTsAst, identifierRegex } from '../utils';
@@ -25,12 +25,11 @@ export function* generateInterpolation(
2525
destructuredPropNames,
2626
templateRefNames,
2727
} = options;
28-
const template = 'template' in options ? options.template : options.sfc.template;
2928

3029
for (
3130
let [section, offset, type] of forEachInterpolationSegment(
3231
ts,
33-
template,
32+
ctx.inlineTsAsts,
3433
destructuredPropNames,
3534
templateRefNames,
3635
ctx,
@@ -94,7 +93,7 @@ type Segment = [
9493

9594
function* forEachInterpolationSegment(
9695
ts: typeof import('typescript'),
97-
template: Sfc['template'],
96+
inlineTsAsts: Map<string, ts.SourceFile> | undefined,
9897
destructuredPropNames: Set<string> | undefined,
9998
templateRefNames: Set<string> | undefined,
10099
ctx: TemplateCodegenContext,
@@ -113,7 +112,7 @@ function* forEachInterpolationSegment(
113112
offset: prefix.length,
114113
});
115114
} else {
116-
const ast = createTsAst(ts, template?.ast, code);
115+
const ast = createTsAst(ts, inlineTsAsts, code);
117116
const varCb = (id: ts.Identifier, isShorthand: boolean) => {
118117
const text = getNodeText(ts, id, ast);
119118
if (!shouldIdentifierSkipped(ctx, text, destructuredPropNames)) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function* generateVFor(
1717

1818
yield `for (const [`;
1919
if (leftExpressionRange && leftExpressionText) {
20-
const collectAst = createTsAst(options.ts, options.template.ast, `const [${leftExpressionText}]`);
20+
const collectAst = createTsAst(options.ts, ctx.inlineTsAsts, `const [${leftExpressionText}]`);
2121
collectVars(options.ts, collectAst, collectAst, forBlockVars);
2222
yield [
2323
leftExpressionText,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function* generateVSlot(
6262
}
6363

6464
if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
65-
const slotAst = createTsAst(options.ts, options.template.ast, `(${slotDir.exp.content}) => {}`);
65+
const slotAst = createTsAst(options.ts, ctx.inlineTsAsts, `(${slotDir.exp.content}) => {}`);
6666
collectVars(options.ts, slotAst, slotAst, slotBlockVars);
6767
yield* generateSlotParameters(options, ctx, slotAst, slotDir.exp, slotVar);
6868
}

packages/language-core/lib/codegen/utils/index.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,16 @@ export function normalizeAttributeValue(node: CompilerDOM.TextNode): [string, nu
6565

6666
export function createTsAst(
6767
ts: typeof import('typescript'),
68-
templateAst: CompilerDOM.RootNode | undefined,
68+
inlineTsAsts: Map<string, ts.SourceFile> | undefined,
6969
text: string,
7070
) {
71-
const inlineTsAsts = (templateAst as any)?.__volar_inlineTsAsts;
7271
let ast = inlineTsAsts?.get(text);
7372
if (!ast) {
7473
ast = ts.createSourceFile('/a.ts', text, 99 satisfies ts.ScriptTarget.ESNext);
7574
inlineTsAsts?.set(text, ast);
7675
}
77-
ast.__volar_used = true;
78-
return ast as ts.SourceFile;
76+
(ast as any).__volar_used = true;
77+
return ast;
7978
}
8079

8180
export function generateSfcBlockSection(

packages/language-core/lib/plugins/vue-template-inline-ts.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { parseInterpolationNode } from '../codegen/template/templateChild';
55
import { parseVForNode } from '../codegen/template/vFor';
66
import { createTsAst } from '../codegen/utils';
77
import type { Code, Sfc, VueLanguagePlugin } from '../types';
8+
import { templateInlineTsAsts } from '../virtualFile/computedSfc';
89

910
const codeFeatures: CodeInformation = {
1011
format: true,
@@ -68,6 +69,7 @@ const plugin: VueLanguagePlugin = ctx => {
6869
return data;
6970
}
7071
const templateContent = sfc.template.content;
72+
const inlineTsAsts = sfc.template.ast && templateInlineTsAsts.get(sfc.template.ast);
7173
let i = 0;
7274
sfc.template.ast.children.forEach(visit);
7375
return data;
@@ -104,7 +106,7 @@ const plugin: VueLanguagePlugin = ctx => {
104106
&& prop.exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY // style='z-index: 2' will compile to {'z-index':'2'}
105107
) {
106108
if (prop.name === 'on' && prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
107-
const ast = createTsAst(ctx.modules.typescript, sfc.template!.ast, prop.exp.content);
109+
const ast = createTsAst(ctx.modules.typescript, inlineTsAsts, prop.exp.content);
108110
if (isCompoundExpression(ctx.modules.typescript, ast)) {
109111
addFormatCodes(
110112
prop.exp.loc.source,

packages/language-core/lib/virtualFile/computedSfc.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { parseCssImports } from '../utils/parseCssImports';
88
import { parseCssVars } from '../utils/parseCssVars';
99
import { computedArray, computedItems } from '../utils/signals';
1010

11+
export const templateInlineTsAsts = new WeakMap<CompilerDOM.RootNode, Map<string, ts.SourceFile>>();
12+
1113
export function computedSfc(
1214
ts: typeof import('typescript'),
1315
plugins: VueLanguagePluginReturn[],
@@ -215,8 +217,11 @@ export function computedSfc(
215217
let inlineTsAsts: Map<string, any> | undefined;
216218

217219
function updateInlineTsAsts(newAst: CompilerDOM.RootNode, oldAst?: CompilerDOM.RootNode) {
218-
const newTsAsts: Map<string, any> = (newAst as any).__volar_inlineTsAsts ??= new Map();
219-
const oldTsAsts: Map<string, any> = (oldAst as any)?.__volar_inlineTsAsts ?? inlineTsAsts;
220+
let newTsAsts = templateInlineTsAsts.get(newAst);
221+
if (!newTsAsts) {
222+
templateInlineTsAsts.set(newAst, newTsAsts = new Map());
223+
}
224+
const oldTsAsts = oldAst && templateInlineTsAsts.get(oldAst) || inlineTsAsts;
220225

221226
if (oldTsAsts) {
222227
for (const [text, ast] of oldTsAsts) {

0 commit comments

Comments
 (0)