Typescript: Type checking/VS Code slow when using MUI

Created on 29 Oct 2019  ·  68Comments  ·  Source: microsoft/TypeScript

TypeScript Version: 3.8.0-dev.20191029

Search Terms: mui, material-ui, typescript, slow

Example Project
https://github.com/jdoklovic/mui-slowness

Expected behavior: Make a bad change to something in src/react/pages/Main.tsx autocomplete seems to be speedy, and error reporting should be too.

Actual behavior: Takes forever to see errors

Related Issues: #32085, #32229, #31817, #30908

Not exactly sure what's going on, but the error reporting in VS Code is super slow.
I've made sure I'm using specific named imports, and I've even forked MUI and mad all of the internal code so the same and removed things like import from '..' but it didn't seem to help.

Here's the output from tsserver logs which doesn't seem to contain anything that jumps out at me.
Also note, I'm using typescript-eslint with the VS Code ESLint extension, not tslint, but eslint seems to be pretty fast.

mui-slowness-tsserver.log

Performance Needs Investigation

Most helpful comment

It's not just errors... Any changes takes enormous time to be processed.

All 68 comments

First off, this bug report is just about perfect, so thanks for that! Second, skipLibCheck usually helps, but you've already got that. Anyone else reading this might want to give that a shot.

I'll look for possible improvements in both TS and the MUI type decls. Thanks!

Thanks @amcasey. Let me know if you need any other data/log dumps or whatever.
Also, I hsould mention that if I launch the app with webpack-dev-server --open --config webpack.react.webview.js the VS Code editor is still super slow to report errors, but if I make a change and save, the watch process/compilation is super fast and usually completes and reloads the browser before VS Code catches up. Not sure if that's useful info or not.

The issue we usually see with responsiveness in MUI consumers is with the large number of icon types. In this case, however, it appears that MUI is using some complicated conditional types to provide sophisticated checking of API usage. I'm experimenting with both tweaking their types and improving compiler perf, but, so far, the solution isn't obvious.

It's not just errors... Any changes takes enormous time to be processed.

I am in compilation hell. 300% CPU and my machine is bricked for 15 minutes.

"@material-ui/core": "^4.3.3",
"@material-ui/icons": "^4.2.1",
"@material-ui/pickers": "^3.2.4",
"@material-ui/styles": "^4.3.3",

"typescript": "^3.7.2",

Any progress with this? Errors take forever to show up and developing with a low-end machine is difficult.

TSC is still incredibly, frustratingly slow for me in any files using MUI. Typically takes anywhere between 5 to 10 seconds from making a change to the type checking to finish and errors being flagged.

When I first open VSC and start the build process, it seems sometimes type checking is relatively fast (1-2 seconds), but becomes slower over time (eventually hitting 5-10 secs). Other times, however, it seems it's also the amount of MUI components used in the working file that impacts TSC speeds.

I remember about 5 months ago I found using specifically TypeScript version 3.3.4000 to actually resolve the slow TSC issues, whereas the following versions were all affected by this slowness. Not tested it since though.

In a small project of mine, I've started to have a watch process with noEmit specifically for *.tsx files. This gives significantly faster feedback (4-5 seconds) if something broke than IntelliSense, which takes forever to update.

Unfortunately, I have yet to find either a solution or a mitigation. I'm reluctant to push a totally new strategy onto the MUI type authors and finding a smaller change with the same effect is much more difficult. Obviously, you do have the option of not using @types/material-ui, but that will make completion a lot less useful and error detection a lot less thorough.

@rrebase @Ravnurin @AlCalzone Having additional (ideally, small) repros would help with this one. Is your code shareable?

I decided to start over with a clean version of @jdoklovic's repro and now I'm seeing a ~3 second delay on startup and then good responsiveness after that (there's a ~2 second lag for squiggles, but that's by design, so they don't flicker, etc). I'm on VS Code 1.40.2 and TS 2.8.0-dev.20191207. I'll try to figure out where those 3 seconds are going, but they're a lot less worrisome than the 12 seconds in the original report.

If people are still seeing longer delays, additional repros would be very helpful. Also, consider giving TS 3.7 a shot, since we made a bunch of perf fixes.

Is your code shareable?

I can email you an archive with the repo in it if that is okay. It currently consists of about 23 TSX and 32 TS files that are relevant to the frontend where I'm seeing the delays. I'll see if I can reduce the size or at least give you some steps how to trigger the longer delays.

@AlCalzone Sure. first.[email protected]

Edit: Please let me know when you do this, since external mail with attached JS is pretty likely to be flagged by IT.

I dug into the 3 second delay and, once again, signs point to And and IsEmptyInterface as the source of the slowdown (since they use complex conditional types that affect type inference). I previously made an attempt to simplify those types, but it had unexpected semantic ramifications and had to be reverted. I'll try again.

@amcasey I hope I find some time later today (CET). I'll let you know here when I send the mail.

@amcasey I sent you an email with the subject "Repro for MUI slowness (AlCalzone)"

Unfortunately, I have yet to find either a solution or a mitigation. I'm reluctant to push a totally new strategy onto the MUI type authors and finding a smaller change with the same effect is much more difficult. Obviously, you do have the option of not using @types/material-ui, but that will make completion a lot less useful and error detection a lot less thorough.

Not sure if not using @types/material-ui is actually an option since material-ui has the types bundled with the package.

@AlCalzone Thanks! Found it in my spam folder. :wink:

@QingqiShi You're quite right. We're usually dealing with typings from DefinitelyTyped and I got mixed up.

@amcasey I resent the mail with the extension changed to zip1 as suggested. If that doesn't work, let me know.

@amcasey have you had a chance to look into the slowdown some more? I can appreciate it's probably one of those that'll take a fair bit of time to fix - If you need an additional sample repro let me know, happy to put something together.

Here's something to try as a workaround if you have a beefy machine:

  • go to Settings in VSCode, and search for 'typescript memory', increase TypeScript › Tsserver: Max TS Server Memory to something like 8192.

I haven't had the opportunity to test this more extensively so if it works please let everyone know :)

My memory was already maxed, so that didn't help me unfortunately.

Same as me. I on a Macbook Pro 2017 (which should be capable enough) and having issues like extreme fan speeds and computer temps. Is there any update on this issue?

I've identified the slow part of the code in the repro that I have and it's complicated enough that compiling slowly seems justifiable, so my next step will be to determine whether the type definitions can be simplified. If that turns out not to be possible, I'll look for ways to speed up handling of this particular class of complex types.

I'm actively working on this, but the changes aren't aimed at any particular TS milestone.

I'm actively working on this, but the changes aren't aimed at any particular TS milestone.

Hi @amcasey,

It seems to me that when the project introduce a generic typed interface, everything becomes dead slow.

I have declared
IFoo<T> { prop1: T; prop2: any; prop3?: any }

Once I use

someMethod(): IFoo<MyType> {
    return { prop1: myTypeObj, prop2: someValue };
}

the whole project and autocomplete became too slow in VS Code.

Please check it is a valid clue for your work.

Typescript version: 3.6.4
VS Code version: 1.41.1

Workspace Extensions: (I think this is too many, but VS Code intellisense, auto-import etc. were responding so fast before I add the generic type in code)

Auto Close Tag v0.5.6
Auto Import v1.5.3
Code Spell Checker v1.7.22
Git Lens - Git supercharged v10.2.0
Intellisense for CSS class names in HTML v1.19.0
JS Refactor v2,20.5
Live Server c5.6.1
npm Intellisense v1.3.0
Paste JSON as Code v12.0.46
sort-imports v6.1.0
TSLint v1.2.3
TypeLens v1.9.3
Visual Studio IntelliCode v1.2.4
Visual Studio Keymap v0.2.0
vscode-icons v9.7.0

@senjacob Thanks for the pointer! Do you have an example of some code that was affected by this? Generic types are incredibly widely used and it would be terrible to discover that they destroy performance across the board.

Not sure if related, but styled-components also suffered a slowdown between 3.3.0 and 3.4.0. https://github.com/microsoft/TypeScript/issues/30663

Thanks, @joeytwiddle! I believe that was the same underlying issue (e.g. https://github.com/microsoft/TypeScript/issues/30819) and should have been addressed by the same fix.

@senjacob Thanks for the pointer! Do you have an example of some code that was affected by this? Generic types are incredibly widely used and it would be terrible to discover that they destroy performance across the board.

@amcasey Thanks for quick reply!

The codebase is private under NDA. Anyway, the finding about generic usage was wrong. Sorry if investigating on it took your valuable time. :(

Disabling TypeLens v1.9.3 extension helped showing the autocomplete result quicker. I wonder why it has started giving me issues only from last week!

Here's something to try as a workaround if you have a beefy machine:

  • go to Settings in VSCode, and search for 'typescript memory', increase TypeScript › Tsserver: Max TS Server Memory to something like 8192.

I haven't had the opportunity to test this more extensively so if it works please let everyone know :)

I ended up trying this btw, and believe I saw a decent improvement. I remember checking memory usage after a lengthy coding session and if I recall correctly VSC was consuming ~6GB, lol.

In a small project of mine, I've started to have a watch process with noEmit specifically for *.tsx files. This gives significantly faster feedback (4-5 seconds) if something broke than IntelliSense, which takes forever to update.

How do you do that ?

I'm actively working on this, but the changes aren't aimed at any particular TS milestone.

@amcasey , may I ask if you made any progress in your investigation ? Is there something we can do locally to mitigate ?
I am thinking for example that if it is a single component that slows the entire project down, we could import it using require, loosing typings only on one component for the benefit of speed.

@SeriousJul https://github.com/mui-org/material-ui/issues/19113 is the best place to track progress on this issue. The short answer is "yes" - we've fixed the regressions and are now looking at whether fundamental performance can be improved.

@amcasey Just to give some additional feedback after working with 3.9 for a while. It is indeed much faster than 3.8 (as I wrote you via e-mail), but its still somewhat painful to work with.
Even on a beefy machine (12-core Ryzen 9, 32 GB RAM), the following editor features are delayed by seconds whenever I edit a file that uses material-ui:

  • auto-completion --> This is especially annoying, since it slows me down
  • quick-fix suggestions / auto-imports
  • error highlighting
  • language server plugins (ESLint, etc...)

@AlCalzone Thanks for the update! Unfortunately, when something is an order of magnitude too slow, even doubling the performance only gets you so far. We're still working on it.

MUI grinds my laptop to a halt.

TSC: 3.7.5

VSC:

Version: 1.44.2
Commit: ff915844119ce9485abfe8aa9076ec76b5300ddd
Date: 2020-04-16T17:50:03.709Z
Electron: 7.1.11
Chrome: 78.0.3904.130
Node.js: 12.8.1
V8: 7.8.279.23-electron.0
OS: Linux x64 5.3.0-46-generic snap

For whatever reason, the same project is much faster in Webstorm, though unfortunately the 'much faster' still means 'painfully slow'.

WebStorm 2020.1
Build #WS-201.6668.106, built on April 6, 2020

@vlopp, it should be dramatically faster (i.e. still painfully slow) in 3.9 beta (and newer).

WebStorm is really fast here using MUI + TS. It gives feedback after less than a second.

@zaguiini I understood WebStorm was based on the same tsserver implementation as VS Code, so my guess would be that they have a heuristic bypassing tsserver in the scenario you're describing. Of course, I can't rule out their having some brilliant secret sauce.

I had the same issue, using MUI in a Typescript context, since I used the MUI components the type checking became very VERY slow (sometimes +15s !). In two projects, one medium size, another big size.

Some days ago I tried this solution https://material-ui.com/guides/minimizing-bundle-size/ which seemed to affect only the bundle size.
After 3 days I can say this changed considerably type checking time (no more than 3s now).
This changed my dev experience on this part of my project. I suggest people who have this issue to try this solution.

For the context, the project which I made the change follows the MUI doc directives, in a sense that imports are perf-safe (there is no import {} from '@material-ui/icons').

If this solution is validated by other people, it would be nice to edit the doc to add a Typescript performance part, something like that.

@Chnapy I'm already doing that. I'm sure it helps the check times, but I have no direct comparison like you do.

@Chnapy I am also already doing that and unfortunately to no avail.

Anyone experienced improvement recently?

I personally replaced import by good old nodejs require.

before (slow):

import Button from "@material-ui/core/Button"

after (no problem):
```ts
const Button = require("@material-ui/core/Button").default
````

in doing so, we loose intelisense for MUI components (no more typechecking when coding) but I guess that's ok, the website documentation is clear and the API straightforward.

in doing so, we loose intelisense for MUI components (no more typechecking when coding) but I guess that's ok, the website documentation is clear and the API straightforward.

@anisg Just to be clear why I don't think that recommendation is helpful is that the desired behaviour is to have the type-checking

Although it may be valid in your case to not have the types checked, the nature of this issue is that when types are being checked it is too slow to be used during development. Your solution does not solve this problem, instead sacrificing type-safety and intelligent linting for a faster build / validation time.

@effervescentia I agree it's just a small workaround, but I do prefer that than having a 300% CPU and a 3s autocompletion.

I'm guessing Automatic Type Acquisition doesn't pull in the type definitions with that style of important, hence no IntelliSense and no delay.

For what it's worth, we haven't dropped this investigation - it's just hard. Basically, the type annotations for MUI require the compiler to do large, complicated computations. In order to speed things up without changing the semantics, we have to design new language features that allow the same constraints to be expressed in a way that can be checked more efficiently.

Out of curiosity, as there were no alternative solutions mentioned yet, is there any chance for this to be an opportunity to split the process into multiple independent phases, or to provide some selective type-checking exclusion rules? If a similar situation ever occurs in the future, I'm sure people would prefer the option to see faster yet less accurate results while they wait for a longer background process, so that at least MUI-unrelated code is easy to work with. Is anything similar reasonable given the current implementation details?

@scscgit That's possible when invoking the compiler through the API and I believe some tools already do, though I believe they only affect CI and not the editing experience. Allowing users to give up some type safety in exchange for improved performance is one of the options we're investigating.

Correct me if I'm wrong, but it's possible that an issue here is the sheer amount of code that needs to be compiled when using something like MUI, which merges JSX, styles, and TS all into one. This combined with the additional declarations necessary to do tree shaking means there is a lot more code to compile than in an app where you might be using SCSS and HTML templates that have separate compilation processes outside of TSC.

@wjohnsto Interestingly, as far as we can tell, that's not the case. It appears that MUI actually takes more time to compile than the simple quantity of source code would suggest. In particular, it combines union types in a way that increases the amount of work geometrically. We're looking for a way to express what it wants to express without generating so many intermediate types.

@amcasey I recently started using xstate and noticed similar slowdowns of the editing experience. Not sure if this has the same underlying issues or something else thats worth looking into.

@AlCalzone Thanks for the update! xstate was on my radar as a complex project, but this is the first report I've heard of a specific performance problem. I don't suppose you can share an affected code fragment?

@amcasey sure thing, here's my current work in progress: https://github.com/AlCalzone/node-zwave-js/blob/b82b0caf28f6eb87d589f6efd9e5bd50357a3836/packages/zwave-js/src/lib/driver/SerialAPICommandMachine.ts

Change the name of any of the states (e.g. waitForACK -> waitForACK2) and notice that the error highlighting can take a couple of seconds to show up:

ezgif com-optimize

@AlCalzone Sorry for the delay - I've been wrestling with a different slow project.

So, I'm seeing the same behavior locally, but I don't know that I would actually have called that out as a delay if you hadn't mentioned it. (For reference, the corresponding delay for MUI tends to be around 10 seconds.) Maybe I'm just used to looking at the worst of the worst. :wink: I'll have a deeper look in case there's something going wrong.

I checked out the commit in your link. Were you expecting the root tsconfig to build cleanly? I'm seeing 68 errors with the workspace version of TypeScript (3.9.4).

It looks like that commit was part of branch fsm/driver, which has advanced since then, but still doesn't build? I didn't see build instructions, so I've been running

npm ci --ignore-scripts
lerna bootstrap
lerna run build

Please let me know if I should be trying something else.

@amcasey no that commit is part of a huge refactor to use xstate, so it doesn't compile yet. I'm only working off the editor features currently. Maybe I'll finally get that branch to build tomorrow or over the weekend.

The repo was bootstrapped using lerna link convert, so npm install && lerna run build should do the job.

Regarding the delay: I'm used to response times of less than 1s, so everything >= 3s is very noticeable.
Especially since auto-imports don't work while typing due to the delay, so I always have to go back a couple of seconds, trigger quick fixes, wait again and then manually select an import.

Yes. I agree that typescript with MUI is very painful. Especially when the project grows large and the auto-completion takes forever to complete. I am also a flutter developer and google's dart language usually takes less than a second to do the analysis job. If this problem cannot be solved then probably I will use dart language to replace the typescript since Auto-import and auto-completion, as well as error detection, are the key in development .

Most of us use MUI for a few buttons and text fields, I mean, there shouldn't be a typescript issue for a basic UI toolkit, Typescript can't be at fault for that, it does a good job the rest of the time. The issue here is MUI.

The pragmatical choice here is to just replace import by require, it will remove typescript computation for MUI and make development smoother, if you need to verify types (eg: check your MUI Theme is correct), just uncomment the line with 'import' to see if it's working. You can also add your own types on top of the MUI API.

I have an older CPU from around ~2010 (I don't play games anymore and also it's useful to know things are still responsive on older hardware). Typescript + MUI is flatly unusable. Every time I type something it sounds like a jet engine spooling up. I'd like to think this shouldn't be a problem but when one of the major UI frameworks isn't supported that poses a risk to long term adoption.

I don't think this is specific to mui but rather large typescript libraries. I'm experiencing something similar using fluent-ui (vscode 1.47.2). When I first open the project the typechecking/intellisense is fast, but after a little while it's becomes very slow.

@badsyntax The meta-issue we're tracking is that large union types can cause performance issues (since there may be combinatorial explosions when they are combined). Most commonly, we've seen this with type declarations that codify some combination of HTML and CSS. If you have a sample project that doesn't fall into this category, I'd love to know more.

Having said that, type declarations in TypeScript are Turing Complete - you can make them do an arbitrarily large amount of work. Some type authors opt to do more work at design time to guarantee better results at runtime. We do our best to give type authors performant ways to express their constraints, but coming up with these abstractions isn't easy.

@amcasey i believe i posted this message in the wrong repository, my apologies. i thought this was the vscode repo. i believe the issue i'm referring to is an editor issue rather than a typescript issue (implied by the eventually degrading performance). sorry for the noise.

any new updates on this, or on the investigation?

@Slmii We've been working on new tools for investigating performance issues (esp the new -generateTrace flag in 4.1 beta), but unfortunately, no other hotspots have been exposed. The issue is still with the size of the unions in withStyles and the ways they're being manipulated. While every release since this was opened has had performance improvements, none have been able to address this specific issue, so none have alleviated the problem (10% faster than "unusable" is still unusable). Sorry I don't have better news.

@amcasey Do you know if this affects projects that aren't using withStyles? I'm guessing it does since the typings would still be included & compiled, but I'm wondering if there's a way to override those specific ones, or conditionally include them. Not sure if Typescript can do that.

@aMoniker The declarations themselves aren't expensive, consuming them is. That's what makes it so hard to profile .d.ts files - you don't know the performance until you have a representative consumer. So my expectation would be that you wouldn't see the same delays if you weren't using withStyles (or other APIs that depend on the same types).

I believe we took a run at bypassing the types entirely and failed to come up with anything satisfactory. There's definitely no way to configure TypeScript to ignore them, but I think we also failed to hack in a competing, cheaper definition. I don't see it on this thread, but it may be in one of the linked bugs. Alternatively, we may have tried it internally and not bothered to post about it after failing utterly. 😄

Was this page helpful?
0 / 5 - 0 ratings

Related issues

blendsdk picture blendsdk  ·  3Comments

bgrieder picture bgrieder  ·  3Comments

jbondc picture jbondc  ·  3Comments

wmaurer picture wmaurer  ·  3Comments

fwanicka picture fwanicka  ·  3Comments