Slow eslint rules

The sonarjs/deprecation and sonarjs/arguments-order are extremely slow relative to other rules in my project. Here’s a sample timing output:

Rule                                        | Time (ms) | Relative
:-------------------------------------------|----------:|--------:
sonarjs/deprecation                         |  9242.197 |    40.9%
react-hooks/react-compiler                  |  6057.107 |    26.8%
sonarjs/no-redundant-assignments            |  1032.823 |     4.6%
sonarjs/aws-restricted-ip-admin-access      |   994.943 |     4.4%
sonarjs/no-dead-store                       |   980.333 |     4.3%
react/display-name                          |   255.277 |     1.1%
@typescript-eslint/no-unnecessary-condition |   254.485 |     1.1%                 .tsx   
react/no-direct-mutation-state              |   185.699 |     0.8%
sonarjs/no-async-constructor                |   180.180 |     0.8%
@typescript-eslint/no-unused-vars           |   176.022 |     0.8%

After disabling sonarjs/deprecation rule sonarjs/arguments-order ended up at the top:

Rule                                        | Time (ms) | Relative
:-------------------------------------------|----------:|--------:
react-hooks/react-compiler                  |  5806.225 |    30.1%
sonarjs/arguments-order                     |  5534.279 |    28.7%
sonarjs/no-redundant-assignments            |  1093.921 |     5.7%
sonarjs/no-dead-store                       |   999.189 |     5.2%
sonarjs/aws-restricted-ip-admin-access      |   993.906 |     5.1%
@typescript-eslint/no-unnecessary-condition |   412.534 |     2.1%
sonarjs/no-async-constructor                |   287.752 |     1.5%
react/display-name                          |   261.780 |     1.4%
@typescript-eslint/no-floating-promises     |   216.520 |     1.1%
react/no-direct-mutation-state              |   203.545 |     1.1%

These are both great rules, but it seems like there may be something wrong with the implementation that is causing them to be extremely expensive performance wise.

Hi @Johannes_B,

Thank you for bringing this up. Looking into these rule implementations:

  1. sonarjs/deprecation - this rule is quite straightforward and only relies on a single method from ts, namely: TypeChecker#getSuggestionDiagnostics . There is not much more we can do.
  2. arguments-order - This one indeed is a bit convoluted and probably the implementation is a bit suboptimal with multiple find and for loops. However, I don’t see anything obvious here.

Just for my understanding the scale that you are working with, how big is the difference for you? How big is your codebase? And I assume that you also have a typescript project?

As the workaround, if you don’t see the value vs time in the rule, then disabling seems like the way to go.

Cheers,
Michal

The “something wrong with the implementation” could be that these rules use TypeScript type information and therefore require a large part of the TypeScript compiler to run. The TypeScript compiler is quite slow.

That the slowness moves from sonarjs/deprecation to sonarjs/arguments-order if the former is disabled may be because both of them need type information, but it is cached after it has been obtained (“charging” the first rule needing it for the time).

If this is indeed the case, there is little that can be done about the rules themselves, and getting rid of the slowdown would require disabling all rules that need type information.

It may be possible to tweak some parts of the code that is being linted so TypeScript can check it faster.

Microsoft is working on a Go version of the TypeScript compiler which is approximately ten times as fast, but ESLint cannot easily use it.

1 Like