From 98b24e800837eda7d3096bf7d9db8ab7400b26bd Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 4 Apr 2024 15:08:43 +0800 Subject: [PATCH] perf: cache canonical root file names with string Set --- packages/component-meta/lib/base.ts | 17 ++------ packages/language-core/lib/languageModule.ts | 26 +++++++++++-- packages/language-server/node.ts | 17 ++------ .../tests/utils/createTester.ts | 17 ++------ .../language-service/tests/utils/format.ts | 4 +- packages/tsc/index.ts | 39 +++++++------------ packages/tsc/tests/dts.spec.ts | 18 ++------- packages/typescript-plugin/index.ts | 17 ++------ 8 files changed, 56 insertions(+), 99 deletions(-) diff --git a/packages/component-meta/lib/base.ts b/packages/component-meta/lib/base.ts index a6d2f499e0..2cdf071171 100644 --- a/packages/component-meta/lib/base.ts +++ b/packages/component-meta/lib/base.ts @@ -160,20 +160,9 @@ export function baseCreate( const vueLanguagePlugin = vue.createVueLanguagePlugin( ts, id => id, - fileName => { - if (ts.sys.useCaseSensitiveFileNames) { - return host.getScriptFileNames().includes(fileName) ?? false; - } - else { - const lowerFileName = fileName.toLowerCase(); - for (const rootFile of host.getScriptFileNames()) { - if (rootFile.toLowerCase() === lowerFileName) { - return true; - } - } - return false; - } - }, + ts.sys.useCaseSensitiveFileNames, + () => host.getProjectVersion?.() ?? '', + () => host.getScriptFileNames(), host.getCompilationSettings(), vueCompilerOptions, ); diff --git a/packages/language-core/lib/languageModule.ts b/packages/language-core/lib/languageModule.ts index 9dc34395ec..058642414a 100644 --- a/packages/language-core/lib/languageModule.ts +++ b/packages/language-core/lib/languageModule.ts @@ -48,14 +48,21 @@ function getFileRegistryKey( return JSON.stringify(values); } +interface _Plugin extends LanguagePlugin { + getCanonicalFileName: (fileName: string) => string; + pluginContext: Parameters[0]; +} + export function createVueLanguagePlugin( ts: typeof import('typescript'), getFileName: (fileId: string) => string, - isValidGlobalTypesHolder: (fileName: string) => boolean, + useCaseSensitiveFileNames: boolean, + getProjectVersion: () => string, + getScriptFileNames: () => string[] | Set, compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions, codegenStack: boolean = false, -): LanguagePlugin { +): _Plugin { const allowLanguageIds = new Set(['vue']); const pluginContext: Parameters[0] = { modules: { @@ -81,11 +88,24 @@ export function createVueLanguagePlugin( allowLanguageIds.add('html'); } + const getCanonicalFileName = useCaseSensitiveFileNames + ? (fileName: string) => fileName + : (fileName: string) => fileName.toLowerCase(); + let canonicalRootFileNames = new Set(); + let canonicalRootFileNamesVersion: string | undefined; + return { + getCanonicalFileName, + pluginContext, createVirtualCode(fileId, languageId, snapshot) { if (allowLanguageIds.has(languageId)) { const fileName = getFileName(fileId); - if (!pluginContext.globalTypesHolder && isValidGlobalTypesHolder(fileName)) { + const projectVersion = getProjectVersion(); + if (projectVersion !== canonicalRootFileNamesVersion) { + canonicalRootFileNames = new Set([...getScriptFileNames()].map(getCanonicalFileName)); + canonicalRootFileNamesVersion = projectVersion; + } + if (!pluginContext.globalTypesHolder && canonicalRootFileNames.has(getCanonicalFileName(fileName))) { pluginContext.globalTypesHolder = fileName; } const fileRegistry = getFileRegistry(pluginContext.globalTypesHolder === fileName); diff --git a/packages/language-server/node.ts b/packages/language-server/node.ts index 1ba352f7b3..0bf136c131 100644 --- a/packages/language-server/node.ts +++ b/packages/language-server/node.ts @@ -80,20 +80,9 @@ connection.onInitialize(async params => { const vueLanguagePlugin = createVueLanguagePlugin( tsdk.typescript, serviceEnv.typescript!.uriToFileName, - fileName => { - if (projectContext.typescript?.sys.useCaseSensitiveFileNames ?? false) { - return projectContext.typescript?.host.getScriptFileNames().includes(fileName) ?? false; - } - else { - const lowerFileName = fileName.toLowerCase(); - for (const rootFile of projectContext.typescript?.host.getScriptFileNames() ?? []) { - if (rootFile.toLowerCase() === lowerFileName) { - return true; - } - } - return false; - } - }, + projectContext.typescript?.sys.useCaseSensitiveFileNames ?? false, + () => projectContext.typescript?.host.getProjectVersion?.() ?? '', + () => projectContext.typescript?.host.getScriptFileNames() ?? [], commandLine?.options ?? {}, vueOptions, options.codegenStack, diff --git a/packages/language-service/tests/utils/createTester.ts b/packages/language-service/tests/utils/createTester.ts index 5e80a559a4..746c6633ff 100644 --- a/packages/language-service/tests/utils/createTester.ts +++ b/packages/language-service/tests/utils/createTester.ts @@ -32,20 +32,9 @@ function createTester(rootUri: string) { const vueLanguagePlugin = createVueLanguagePlugin( ts, serviceEnv.typescript!.uriToFileName, - fileName => { - if (ts.sys.useCaseSensitiveFileNames) { - return projectHost.getScriptFileNames().includes(fileName); - } - else { - const lowerFileName = fileName.toLowerCase(); - for (const rootFile of projectHost.getScriptFileNames()) { - if (rootFile.toLowerCase() === lowerFileName) { - return true; - } - } - return false; - } - }, + ts.sys.useCaseSensitiveFileNames, + () => projectHost.getProjectVersion?.() ?? '', + () => projectHost.getScriptFileNames(), parsedCommandLine.options, parsedCommandLine.vueOptions, ); diff --git a/packages/language-service/tests/utils/format.ts b/packages/language-service/tests/utils/format.ts index d1b5242766..be4d218d09 100644 --- a/packages/language-service/tests/utils/format.ts +++ b/packages/language-service/tests/utils/format.ts @@ -7,7 +7,9 @@ const resolvedVueOptions = resolveVueCompilerOptions({}); const vueLanguagePlugin = createVueLanguagePlugin( ts, fileId => formatter.env.typescript!.uriToFileName(fileId), - () => false, + false, + () => '', + () => [], {}, resolvedVueOptions, ); diff --git a/packages/tsc/index.ts b/packages/tsc/index.ts index 1ec48a4c43..c6e5357538 100644 --- a/packages/tsc/index.ts +++ b/packages/tsc/index.ts @@ -16,37 +16,28 @@ export function run() { const vueOptions = typeof configFilePath === 'string' ? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions : vue.resolveVueCompilerOptions({}); - const writeFile = options.host!.writeFile.bind(options.host); - const getCanonicalFileName = options.host?.useCaseSensitiveFileNames?.() - ? (fileName: string) => fileName - : (fileName: string) => fileName.toLowerCase(); - const canonicalRootFileNames = new Set( - options.rootNames - .map(rootName => rootName.replace(windowsPathReg, '/')) - .map(getCanonicalFileName) - ); - const canonicalGlobalTypesHolderFileNames = new Set(); - options.host!.writeFile = (fileName, contents, ...args) => { - if ( - fileName.endsWith('.d.ts') - && canonicalGlobalTypesHolderFileNames.has(getCanonicalFileName(fileName.replace(windowsPathReg, '/')).slice(0, -5)) - ) { - contents = removeEmitGlobalTypes(contents); - } - return writeFile(fileName, contents, ...args); - }; if ( runExtensions.length === vueOptions.extensions.length && runExtensions.every(ext => vueOptions.extensions.includes(ext)) ) { + const writeFile = options.host!.writeFile.bind(options.host); + options.host!.writeFile = (fileName, contents, ...args) => { + if ( + fileName.endsWith('.d.ts') + && vueLanguagePlugin + .getCanonicalFileName(fileName.replace(windowsPathReg, '/')) + .slice(0, -5) === vueLanguagePlugin.pluginContext.globalTypesHolder + ) { + contents = removeEmitGlobalTypes(contents); + } + return writeFile(fileName, contents, ...args); + }; const vueLanguagePlugin = vue.createVueLanguagePlugin( ts, id => id, - fileName => { - const canonicalFileName = getCanonicalFileName(fileName); - canonicalGlobalTypesHolderFileNames.add(canonicalFileName); - return canonicalRootFileNames.has(canonicalFileName); - }, + options.host?.useCaseSensitiveFileNames?.() ?? false, + () => '', + () => options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')), options.options, vueOptions, false, diff --git a/packages/tsc/tests/dts.spec.ts b/packages/tsc/tests/dts.spec.ts index 956a843ff9..d2ad168b24 100644 --- a/packages/tsc/tests/dts.spec.ts +++ b/packages/tsc/tests/dts.spec.ts @@ -35,21 +35,9 @@ describe('vue-tsc-dts', () => { const vueLanguagePlugin = vue.createVueLanguagePlugin( ts, id => id, - fileName => { - const rootFileNames = options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')); - if (options.host?.useCaseSensitiveFileNames?.()) { - return rootFileNames.includes(fileName); - } - else { - const lowerFileName = fileName.toLowerCase(); - for (const rootFileName of rootFileNames) { - if (rootFileName.toLowerCase() === lowerFileName) { - return true; - } - } - return false; - } - }, + options.host?.useCaseSensitiveFileNames?.() ?? false, + () => '', + () => options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')), options.options, vueOptions, false, diff --git a/packages/typescript-plugin/index.ts b/packages/typescript-plugin/index.ts index 756885472f..6ef31043a6 100644 --- a/packages/typescript-plugin/index.ts +++ b/packages/typescript-plugin/index.ts @@ -30,20 +30,9 @@ function createLanguageServicePlugin(): ts.server.PluginModuleFactory { const languagePlugin = vue.createVueLanguagePlugin( ts, id => id, - fileName => { - if (info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false) { - return externalFiles.get(info.project)?.has(fileName) ?? false; - } - else { - const lowerFileName = fileName.toLowerCase(); - for (const externalFile of externalFiles.get(info.project) ?? []) { - if (externalFile.toLowerCase() === lowerFileName) { - return true; - } - } - return false; - } - }, + info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false, + () => info.languageServiceHost.getProjectVersion?.() ?? '', + () => externalFiles.get(info.project) ?? [], info.languageServiceHost.getCompilationSettings(), vueOptions, );