Skip to content

Commit 3bfd059

Browse files
perf(typescript-plugin): redo single-file language service for Reactivity Visualization (#5652)
1 parent b274db2 commit 3bfd059

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

packages/typescript-plugin/index.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,17 +189,15 @@ export = createLanguageServicePlugin(
189189
});
190190
session.addProtocolHandler('_vue:getReactiveReferences', request => {
191191
const [fileName, position]: Parameters<Requests['getReactiveReferences']> = request.arguments;
192-
const { languageService, language } = getLanguageService(fileName);
193-
const sourceScript = language.scripts.get(fileName);
192+
const { language } = getLanguageService(fileName);
193+
const sourceScript = language.scripts.get(fileName)!;
194194
return createResponse(
195195
getReactiveReferences(
196196
ts,
197197
language,
198-
languageService,
199198
sourceScript,
200-
fileName,
201199
position,
202-
sourceScript?.generated ? sourceScript.snapshot.getLength() : 0,
200+
sourceScript.generated ? sourceScript.snapshot.getLength() : 0,
203201
),
204202
);
205203
});

packages/typescript-plugin/lib/requests/getReactiveReferences.ts

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
/// <reference types="@volar/typescript" />
2-
1+
import { createProxyLanguageService, decorateLanguageServiceHost } from '@volar/typescript';
32
import { collectBindingRanges, hyphenateAttr, type Language, type SourceScript } from '@vue/language-core';
43
import type * as ts from 'typescript';
54

@@ -27,21 +26,58 @@ interface ReactiveNode {
2726
callback?: TSNode;
2827
}
2928

29+
let currentVersion = -1;
30+
let currentFileName = '';
31+
let currentSnapshot: ts.IScriptSnapshot | undefined;
32+
let languageService: ts.LanguageService | undefined;
33+
let languageServiceHost: ts.LanguageServiceHost | undefined;
34+
3035
const analyzeCache = new WeakMap<ts.SourceFile, ReturnType<typeof analyze>>();
3136

3237
export function getReactiveReferences(
3338
ts: typeof import('typescript'),
34-
language: Language,
35-
languageService: ts.LanguageService,
36-
sourceScript: SourceScript | undefined,
37-
fileName: string,
39+
language: Language<string>,
40+
sourceScript: SourceScript<string>,
3841
position: number,
3942
leadingOffset: number = 0,
4043
) {
41-
const serviceScript = sourceScript?.generated?.languagePlugin.typescript?.getServiceScript(
44+
if (currentSnapshot !== sourceScript.snapshot || currentFileName !== sourceScript.id) {
45+
currentSnapshot = sourceScript.snapshot;
46+
currentFileName = sourceScript.id;
47+
currentVersion++;
48+
}
49+
if (!languageService) {
50+
languageServiceHost = {
51+
getProjectVersion: () => currentVersion.toString(),
52+
getScriptVersion: () => currentVersion.toString(),
53+
getScriptFileNames: () => [currentFileName],
54+
getScriptSnapshot: fileName => fileName === currentFileName ? currentSnapshot : undefined,
55+
getCompilationSettings: () => ({ allowJs: true, allowNonTsExtensions: true }),
56+
getCurrentDirectory: () => '',
57+
getDefaultLibFileName: () => '',
58+
readFile: () => undefined,
59+
fileExists: fileName => fileName === currentFileName,
60+
};
61+
decorateLanguageServiceHost(ts, language, languageServiceHost);
62+
const proxied = createProxyLanguageService(ts.createLanguageService(languageServiceHost));
63+
proxied.initialize(language);
64+
languageService = proxied.proxy;
65+
}
66+
return getReactiveReferencesWorker(ts, language, languageService, sourceScript, position, leadingOffset);
67+
}
68+
69+
function getReactiveReferencesWorker(
70+
ts: typeof import('typescript'),
71+
language: Language<string>,
72+
languageService: ts.LanguageService,
73+
sourceScript: SourceScript<string>,
74+
position: number,
75+
leadingOffset: number,
76+
) {
77+
const serviceScript = sourceScript.generated?.languagePlugin.typescript?.getServiceScript(
4278
sourceScript.generated.root,
4379
);
44-
const map = serviceScript ? language.maps.get(serviceScript.code, sourceScript!) : undefined;
80+
const map = serviceScript ? language.maps.get(serviceScript.code, sourceScript) : undefined;
4581
const toSourceRange = map
4682
? (start: number, end: number) => {
4783
for (const [mappedStart, mappedEnd] of map.toSourceRange(start - leadingOffset, end - leadingOffset, false)) {
@@ -57,7 +93,7 @@ export function getReactiveReferences(
5793
}
5894
};
5995

60-
const sourceFile = languageService.getProgram()!.getSourceFile(fileName)!;
96+
const sourceFile = languageService.getProgram()!.getSourceFile(sourceScript.id)!;
6197

6298
if (!analyzeCache.has(sourceFile)) {
6399
analyzeCache.set(sourceFile, analyze(ts, sourceFile, toSourceRange, toSourceNode));

0 commit comments

Comments
 (0)