Repository navigation
Project references decrease performance of language service by a factor of 10 #42607
Description
Bug Report
We have a large mono repo with around 10000 tsconfig.json projects in a nested directory structure configured with project references. We've been finding the performance of type checking and suggestions in both VSCode and Intellij is becoming unbearably slow, especially in projects that have a lot project ref dependencies (including transitive). For example, it's common for type errors and suggestions to take greater than 20 seconds to update and appear. I have tried doing a tsc -b on the root projects so the d.ts files are available on disk, but that doesn't seem to help.
However, I found after deleting the references field in the tsconfig files, the IDE response time reduces to 500ms, a huge improvement that makes editing a lot easier. This surprises me as I thought project references would improve performance, not decrease it. Keeping the references field but setting composite to false is still slow.
I verified the times by looking at updateGraphWorker events in the VSCode ts server logs, but the difference is also very visible without the logs.
Thanks for your help!
A sample project:
{
"include": [
"../../../../declarations/css_modules.d.ts",
"./**/*.*"
],
"compilerOptions": {
"types": []
},
"references": [
{ "path": "../../../base" },
{ "path": "../../../base/foo" },
{ "path": "./banana" },
],
"exclude": [
"banana",
"stories",
"tests"
],
"extends": "../../../../tsconfig.build.json"
}
The inherited tsconfig.build.json config:
{
"compilerOptions": {
"composite": true,
"declaration": true,
"declarationMap": true,
"baseUrl": "./src",
"experimentalDecorators": true,
"importHelpers": true,
"jsx": "react",
"lib": [
"dom",
"dom.iterable",
"es2018",
"es2019.array"
],
"moduleResolution": "node",
"rootDir": ".",
"outDir": "target",
"strict": true,
"skipLibCheck": true,
"target": "ES2019",
"sourceMap": true,
"inlineSources": true,
"module": "ESNext",
"types": [],
"paths": {
"base": ["../node_modules/base/"],
"mobx": ["../declarations/mobx"]
}
},
// Don't include any source files in the base build.
"include": []
}
🔎 Search Terms
language service intellisense project references performance
🕗 Version & Regression Information
Version 4.1.2
🙁 Actual behavior
Language service performance degrades when project references are defined.
🙂 Expected behavior
Language service performance does not degrade when project references are defined.
Activity
ajafff commentedon Feb 2, 2021
That doesn't help because by default TypeScript will load the source files of referenced projects instead of their declaration files. That means in the worst case you have one project that loads and watches all files from your 1000 other projects.
There's a compilerOption
disableSourceOfProjectReferenceRedirectthat disables that behavior in the language service and only loads the declaration files. But that means you always have to compile referenced projects to get up-to-date type information in dependent projects while editing.WearyMonkey commentedon Feb 2, 2021
Thanks Klaus Meinhardt (@ajafff) I've tried
disableSourceOfProjectReferenceRedirectand verified via the service logs that its openingd.tsfiles but it didn't help performance. I also trieddisableReferencedProjectLoadto no avail.WearyMonkey commentedon Feb 2, 2021
I've added a custom language service plugin:
And that does have the same effect of removing the project refs from the tsconfig.json files, improving performance significantly.
sheetalkamat commentedon Feb 3, 2021
We would need tsserver log to see whats going on what could be causing the delays..
WearyMonkey commentedon Feb 4, 2021
Thanks Sheetal Nandi (@sheetalkamat) . Do you have any tools or guidance for sanitising the logs so they don't contain any private IP? It looks like they contain source file names and some source content / ASTs?
Or is there someway we can send the logs in private?
Thanks!
WearyMonkey commentedon Feb 4, 2021
Sheetal Nandi (@sheetalkamat) I took some CPU profiles with and without the project references.
With project references, about 4s is spent in
canReuseProjectReferences.It looks like on every change the language service needs to re-parse every
tsconfig.jsonfile, which is 7000 for us. It also needs walk the directory structure of every project as well.I tried hard coding
canReuseProjectReferencesto true, but the following line intryReuseStructureFromOldProgramcauses a reparse anyway.sheetalkamat commentedon Feb 4, 2021
As part of #37304 investigation i am trying to cache the project rereference parsing so that might help i think.
WearyMonkey commentedon Feb 4, 2021
Thanks Sheetal Nandi (@sheetalkamat)! I can help with testing any changes on our large code base.
sheetalkamat commentedon Mar 9, 2021
Toby Rahilly (@WearyMonkey) can you please test this with #42929 (comment) and see if there are improvements. Thanks
WearyMonkey commentedon Mar 10, 2021
Sheetal Nandi (@sheetalkamat)
here are my timings:
To test, I added the line
const foo: string = 1;to a root package in our project with thousands of transitive dependencies.Initial load is the initial
updateGraphWorkertime.Update 1 is
updateGraphWorkerwhen changing toconst foo: number = 1;Update 2 is
updateGraphWorkerwhen changing toconst foo: string = 1;Update 3 is
updateGraphWorkerwhen changing toconst foo: number = 1;Interestingly I noticed updateGraphWorker is called twice per update, each taking roughly the same amount of time. So the above numbers are the sum of both
updateGraphWorkertasks.The no refs times are with my hacky plugin which removes the project references:
So all in, a huge improvement, nice work! 👏 Super excited for 4.3 now.
WearyMonkey commentedon Mar 10, 2021
Sorry got the data columns in wrong order in initial reply, fixed now but pointing it out in case you already looked at the wrong version.
You can see there is a slight increase in initial load time for 4.3, which isn't as much as an issue as the update times.
sheetalkamat commentedon Mar 10, 2021
Can you please share numbers on 4.3 with typescript@next and with #42929 and their corresponding tsserver log so i can look through if there is something we are missing or some issues with how updates are happening. (Would prefer if you can disable all plugins and extensions).
Thanks
WearyMonkey commentedon Mar 10, 2021
I can't share the log sorry, it contains too much IP.