From 4027ee777f5a3e24578bda6a3e019ac8fc861d16 Mon Sep 17 00:00:00 2001 From: Blake Newman Date: Thu, 23 Nov 2023 11:23:43 +0000 Subject: [PATCH] perf(tsc): support vue files with project reference delcaration Support vue files with project reference output, so that typescript resolves the project reference vue file as the output `vue.d.ts` file rather than the source. This drastically improves performance in large projects that have vue files imported from project references. As much as 50% performance improvements as ts no longer recompiles vue files from source. Setup the real path to pass back the real path of vue files, as they are virtual files the inbuilt realpath always returns the non symlinked version (node_modules), which affects DX with vue-tsc as errors originating from upstream project reference packages are returned with the node modules path rather than the source. This change is also required to power the usage of `d.ts` files. --- packages/tsc/src/index.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/tsc/src/index.ts b/packages/tsc/src/index.ts index 5f6be90e49..a02df68b92 100644 --- a/packages/tsc/src/index.ts +++ b/packages/tsc/src/index.ts @@ -64,7 +64,7 @@ export function createProgram(options: ts.CreateProgramOptions) { modifiedTime: number, scriptSnapshot: ts.IScriptSnapshot, }>(); - const languageHost: vue.TypeScriptLanguageHost = { + const languageHost: vue.TypeScriptLanguageHost & Partial = { workspacePath: ctx.options.host!.getCurrentDirectory().replace(windowsPathReg, '/'), rootPath: ctx.options.host!.getCurrentDirectory().replace(windowsPathReg, '/'), getCompilationSettings: () => ctx.options.options, @@ -77,6 +77,21 @@ export function createProgram(options: ts.CreateProgramOptions) { }, getProjectReferences: () => ctx.options.projectReferences, getCancellationToken: ctx.options.host!.getCancellationToken ? () => ctx.options.host!.getCancellationToken!() : undefined, + realpath(path) { + const realpath = ctx.options.host!.realpath! ?? ts.sys.realpath + const match = /^(?.+\.vue)\.(?.+)$/.exec(path) + return match?.groups ? `${realpath(match.groups.path)}.${match.groups.extension}` : realpath(path) + }, + getParsedCommandLine: (path) => { + const possibleExtensions = ['ts', 'tsx'] + const { fileNames, ...commandLineCustom } = vue.createParsedCommandLine(ts, ts.sys, path) + // need to outDir to be defined + const commandLine = ts.getParsedCommandLineOfConfigFile(path, undefined, ts.sys as any) ?? commandLineCustom + return { + ...commandLine, + fileNames: fileNames.flatMap(name => name.endsWith('.vue') ? possibleExtensions.map(ext => `${name}.${ext}`) : [name]) + } + }, }; const languageContext = vue.createLanguageContext( languageHost,