You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm currently investigating a performance issue with TypeScript as part of a lint task with eslint and @typescript/eslint-plugin. Looking at a CPU trace (generated via node --cpu-prof) I can see that TypeScript's getSourceVersion takes up 8% of the total linting time.
Note: This is a left-heavy flamegraph, meaning bars don't represent individual calls
The implementation of that function looks pretty harmless, so I did some further digging and noticed that this function is called a whopping 33,000,000 times during the whole duration of the linting task. Whereas the compiler host only has references to a few thousand files in its caches. Note that eslint is NOT running in watch mode, and no files changed on disk.
What's even more odd is that the surrounding sourceFileNotUptoDate function always returns false. This leads me to suspect that files are checked despite nothing having changed. Following the callstack, the origin where those up-to-date checks original from resides in @typescript-eslint/typescript-estree:
letfileList=programFileListCache.get(tsconfigPath);letupdatedProgram: ts.Program|null=null;if(!fileList){updatedProgram=existingWatch.getProgram().getProgram();fileList=updateCachedFileList(tsconfigPath,updatedProgram,parseSettings,);}if(fileList.has(filePath)){log('Found existing program for file. %s',filePath);updatedProgram=updatedProgram??existingWatch.getProgram().getProgram();// <-- THIS HERE TRIGGERS ALL FILES TO BE RE-CHECKED// sets parent pointers in source filesupdatedProgram.getTypeChecker();return[updatedProgram];}
Based on that my understanding is that whenever eslint comes across a new file that should be linted, it may already be loaded by TypeScript itself. From what I'm gathering an additional call to .getProgram().getProgram() forces TypeScript to re-evaluate the whole world and check if every single file it knows about changed.
I've tried creating a reproducible scenario that could be shared from that project, but I haven't been able to do so after a day of trying.
I'm unsure how to proceed from here and need some guidance with folks more familiar with TypeScript's internals and how the compiler API is supposed to be used. My initial reaction was that it's a bit unexpected that .getProgram() re-evaluates every file. Or maybe there is a different API that should be used instead? Is it maybe a misusage of .getProgram() and the result should be manually cached instead?
Could very well be that a custom module resolver was used. I'm not part of the project anymore where I encountered that issue so I cannot check. Closing this issue since there is no actionable step.
Bug Report
I'm currently investigating a performance issue with TypeScript as part of a lint task with
eslint
and@typescript/eslint-plugin
. Looking at a CPU trace (generated vianode --cpu-prof
) I can see that TypeScript'sgetSourceVersion
takes up 8% of the total linting time.Note: This is a left-heavy flamegraph, meaning bars don't represent individual calls
The implementation of that function looks pretty harmless, so I did some further digging and noticed that this function is called a whopping 33,000,000 times during the whole duration of the linting task. Whereas the compiler host only has references to a few thousand files in its caches. Note that
eslint
is NOT running in watch mode, and no files changed on disk.What's even more odd is that the surrounding
sourceFileNotUptoDate
function always returnsfalse
. This leads me to suspect that files are checked despite nothing having changed. Following the callstack, the origin where those up-to-date checks original from resides in@typescript-eslint/typescript-estree
:https://github.com/typescript-eslint/typescript-eslint/blob/4ab9bd7f7c1812df4371d1fd3202969c1039e8a7/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts#L194
Based on that my understanding is that whenever
eslint
comes across a new file that should be linted, it may already be loaded by TypeScript itself. From what I'm gathering an additional call to.getProgram().getProgram()
forces TypeScript to re-evaluate the whole world and check if every single file it knows about changed.I've tried creating a reproducible scenario that could be shared from that project, but I haven't been able to do so after a day of trying.
I'm unsure how to proceed from here and need some guidance with folks more familiar with TypeScript's internals and how the compiler API is supposed to be used. My initial reaction was that it's a bit unexpected that
.getProgram()
re-evaluates every file. Or maybe there is a different API that should be used instead? Is it maybe a misusage of.getProgram()
and the result should be manually cached instead?🔎 Search Terms
Performance, eslint, @typescript-eslint, eslint-plugin
🕗 Version & Regression Information
This changed between versions ______ and _______- Doesn't seem to be a regressionI was unable to test this on prior versions becauseOldest version I tested was4.7.2
where the issue is present too.⏯ Playground Link
I've tried creating a reproducible scenario that could be shared from that project, but I'm haven't been able to do so after a day of trying.
💻 Code
see above.
🙁 Actual behavior
TypeScript does a lot more checks if files are up to date than expected, despite nothing having changed on disk.
🙂 Expected behavior
TypeScript only checks if something changed if a file actually changed or a specific file is invalidated via some API call.
The text was updated successfully, but these errors were encountered: