diff --git a/packages/language-server/package.json b/packages/language-server/package.json index fc66d7b54..612883700 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -58,6 +58,7 @@ "svelte-preprocess": "~5.1.0", "svelte2tsx": "workspace:~", "typescript": "^5.3.2", + "typescript-auto-import-cache": "^0.3.0", "vscode-css-languageservice": "~6.2.10", "vscode-html-languageservice": "~5.1.1", "vscode-languageserver": "8.0.2", diff --git a/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts b/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts index 2d438cedb..45cb586d7 100644 --- a/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts +++ b/packages/language-server/src/plugins/typescript/LSAndTSDocResolver.ts @@ -71,6 +71,10 @@ export class LSAndTSDocResolver { this.getCanonicalFileName = createGetCanonicalFileName( (options?.tsSystem ?? ts.sys).useCaseSensitiveFileNames ); + + configManager.onChange(() => { + this.configChanged = true; + }); } /** @@ -96,6 +100,8 @@ export class LSAndTSDocResolver { private extendedConfigCache = new Map(); private getCanonicalFileName: GetCanonicalFileName; + private configChanged = true; + private get lsDocumentContext(): LanguageServiceDocumentContext { return { ambientTypesSource: this.options?.isSvelteCheck ? 'svelte-check' : 'svelte2tsx', @@ -121,6 +127,11 @@ export class LSAndTSDocResolver { }> { const { tsDoc, lsContainer, userPreferences } = await this.getLSAndTSDocWorker(document); + if (this.configChanged) { + this.configChanged = false; + lsContainer.setUserPreferences(userPreferences); + } + return { tsDoc, lang: lsContainer.getService(), userPreferences }; } diff --git a/packages/language-server/src/plugins/typescript/service.ts b/packages/language-server/src/plugins/typescript/service.ts index 09cac7fba..e0f3da4ee 100644 --- a/packages/language-server/src/plugins/typescript/service.ts +++ b/packages/language-server/src/plugins/typescript/service.ts @@ -21,6 +21,7 @@ import { hasTsExtensions, isSvelteFilePath } from './utils'; +import { createLanguageService as createLanguageServiceWithCache } from 'typescript-auto-import-cache'; export interface LanguageServiceContainer { readonly tsconfigPath: string; @@ -47,6 +48,8 @@ export interface LanguageServiceContainer { */ fileBelongsToProject(filePath: string, isNew: boolean): boolean; + setUserPreferences(preferences: ts.UserPreferences): void; + dispose(): void; } @@ -302,7 +305,6 @@ async function createLanguageService( tsSystem.useCaseSensitiveFileNames ); - const languageService = ts.createLanguageService(host, documentRegistry); const transformationConfig: SvelteSnapshotOptions = { parse: svelteCompiler?.parse, version: svelteCompiler?.VERSION, @@ -310,6 +312,14 @@ async function createLanguageService( typingsNamespace: raw?.svelteOptions?.namespace || 'svelteHTML' }; + const serviceWithCache = createLanguageServiceWithCache( + ts as any, + tsSystemWithPackageJsonCache, + host, + () => ts.createLanguageService(host, documentRegistry) + ); + const { languageService } = serviceWithCache; + docContext.globalSnapshotsManager.onChange(scheduleUpdate); reduceLanguageServiceCapabilityIfFileSizeTooBig(); @@ -329,6 +339,7 @@ async function createLanguageService( fileBelongsToProject, snapshotManager, invalidateModuleCache, + setUserPreferences, dispose }; @@ -368,6 +379,8 @@ async function createLanguageService( if (!prevSnapshot) { svelteModuleLoader.deleteUnresolvedResolutionsFromCache(filePath); + // @ts-expect-error + host?.getCachedExportInfoMap()?.clear(); } const newSnapshot = DocumentSnapshot.fromDocument(document, transformationConfig); @@ -443,9 +456,20 @@ async function createLanguageService( function updateProjectFiles(): void { projectVersion++; dirty = true; - const projectFileCountBefore = snapshotManager.getProjectFileNames().length; + const projectFileBefore = snapshotManager.getProjectFileNames(); + const projectFileCountBefore = projectFileBefore.length; snapshotManager.updateProjectFiles(); - const projectFileCountAfter = snapshotManager.getProjectFileNames().length; + const projectFileAfter = snapshotManager.getProjectFileNames(); + const projectFileCountAfter = projectFileAfter.length; + + const hasAddedOrRemoved = + projectFileCountAfter !== projectFileCountBefore || + checkProjectFileUpdate(projectFileBefore, projectFileAfter); + + if (hasAddedOrRemoved) { + // @ts-expect-error + host?.getCachedExportInfoMap()?.clear(); + } if (projectFileCountAfter <= projectFileCountBefore) { return; @@ -454,6 +478,25 @@ async function createLanguageService( reduceLanguageServiceCapabilityIfFileSizeTooBig(); } + function checkProjectFileUpdate(oldFiles: string[], newFiles: string[]) { + const oldSet = new Set(oldFiles); + const newSet = new Set(newFiles); + + for (const file of oldSet) { + if (!newSet.has(file)) { + return true; + } + } + + for (const file of newSet) { + if (!oldSet.has(file)) { + return true; + } + } + + return false; + } + function getScriptFileNames() { const projectFiles = languageServiceReducedMode ? [] @@ -645,6 +688,10 @@ async function createLanguageService( } } + function setUserPreferences(userPreferences: ts.UserPreferences) { + serviceWithCache.setPreferences?.(userPreferences); + } + function dispose() { languageService.dispose(); snapshotManager.dispose(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1fb51a95..cd08d4437 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -60,6 +60,9 @@ importers: typescript: specifier: ^5.3.2 version: 5.3.2 + typescript-auto-import-cache: + specifier: ^0.3.0 + version: 0.3.0 vscode-css-languageservice: specifier: ~6.2.10 version: 6.2.10 @@ -1924,6 +1927,12 @@ packages: engines: {node: '>=4'} dev: true + /typescript-auto-import-cache@0.3.0: + resolution: {integrity: sha512-Rq6/q4O9iyqUdjvOoyas7x/Qf9nWUMeqpP3YeTaLA+uECgfy5wOhfOS+SW/+fZ/uI/ZcKaf+2/ZhFzXh8xfofQ==} + dependencies: + semver: 7.5.1 + dev: false + /typescript@5.3.2: resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} engines: {node: '>=14.17'}