DWilches
DWilches

Reputation: 23035

Angular project with eslint is super slow

I have an Angular12 project composed of 590 TypeScript files. When I do ng lint it runs TSLint and finishes in about 5 seconds. Nonetheless, I tried upgrading to eslint following the instructions on this official video from Angular, and now ng lint takes more than 10 minutes (I actually didn't let the process finish, I stopped it at the 10 minutes mark).

I tried to isolate the issue to know if the cause was ng or eslint so I installed eslint globally with npm i -g eslint and run it with timing information for a single file:

time TIMING=1 eslint /home/user/my-file.ts

And even for this single file it took more than 2 minutes. It is odd that eslint is reporting each rule took just some milliseconds, whereas Linux says it took 148 seconds (which is accurate, it took more than 2 minutes):

Rule                                        | Time (ms) | Relative
:-------------------------------------------|----------:|--------:
@angular-eslint/no-conflicting-lifecycle    |     0.342 |    35.9%
@angular-eslint/no-input-rename             |     0.163 |    17.1%
@angular-eslint/template/banana-in-box      |     0.161 |    16.9%
@angular-eslint/no-output-rename            |     0.103 |    10.9%
@angular-eslint/component-class-suffix      |     0.100 |    10.5%
@angular-eslint/contextual-lifecycle        |     0.083 |     8.7%
@angular-eslint/directive-class-suffix      |     0.000 |     0.0%
@angular-eslint/no-empty-lifecycle-method   |     0.000 |     0.0%
@angular-eslint/no-host-metadata-property   |     0.000 |     0.0%
@angular-eslint/no-inputs-metadata-property |     0.000 |     0.0%
Rule | Time (ms) | Relative
:----|----------:|--------:
TIMING=1 eslint   148.14s user 4.47s system 190% cpu 1:19.96 total

How can I make eslint go faster?

Upvotes: 25

Views: 10531

Answers (4)

Rudy A. Hernandez
Rudy A. Hernandez

Reputation: 495

The underlying issue is still the overhead of the TypeScript compiler generating an AST (Abstract Syntax Tree), and the @typescript-eslint/typescript-estree work of converting this AST to an ESLint compatible AST.

However, there are some minor tweaks:

  • Set up .eslintignore to ignore irrelevant directories like node_modules and non-TypeScript files
  • Use the --cache flag when running eslint: eslint --cache \*\*/\_.ts. Store the info about processed files in order to only operate on the changed ones, or you may config the angular.json file's lint section with "cache": true.

There is also a whole article on TypeScript performance which recommends:

  • Set up tsconfig.json with the include property to specify only input folders in a project with TypeScript files that should be compiled.
  • Avoid adding too many exclude and include folders, since TypeScript files must be discovered by walking through included directories, so running through many folders can actually slow down compilation.

Upvotes: 7

Rapido
Rapido

Reputation: 372

For some reasons, removing from tsconfig.json

"exclude": [
    ...
]

or adding

"include": [
    ...
]

Makes huge improvements when running npm run lint / ng lint.

In my case time TIMING=1 npx eslint ./src/ or time ng lint was running for exactly the same time.

Upvotes: -1

Wilt
Wilt

Reputation: 44393

Check the Notes on Performance in the Angular es-lint guide

I suggest carefully reading through this section titled Notes on Performance of the Angular ts-lint to es-lint migration guide.

You can start debugging your problem by running the following command:

DEBUG=typescript-eslint:* ng lint 

You will get an enormous amount of output, but there could be some valuable information in there.

  • Check (in one of the first lines) whether the expected tsconfig files are loaded.

  • Check the output for files that are actually not supposed to be part of the linting process (i.e. from node_modules folder or dist folder, etc). This might expose some configuration issues for which you have to dig deeper.

Also check whether you get a lot of output as follows:

typescript-eslint:typescript-estree:createProjectProgram Creating project program for: path\to\your\file +0ms
typescript-eslint:typescript-estree:createWatchProgram File did not belong to any existing programs, moving to create/update. path\to\your\file +0ms
typescript-eslint:typescript-estree:createWatchProgram Creating watch program for path\to\your\file +0ms

If that is the case have a good look at the files and path names inside your tsconfig. Specifically "baseUrl", "include" and "exclude" paths.


Note: I had for example "exclude" paths for spec files, but because of a configuration issue they were actually not excluded correctly and creating project programs for these files individually was slowing down the linting dramatically.


Consider limiting linting to changes only

If after resolving all performance issues mentioned above does still not give you the performance you were hoping for you could also consider limiting the linting to changed files only.

This can be done by using the "cache" option in the lint options in your angular.json file (normally the --cache flag for eslint):

"lint": {
  "builder": "@angular-eslint/builder:lint",
  "options": {
    "cache": true,
    ...
  }
}

Upvotes: 8

Transformer
Transformer

Reputation: 7439

First I would double check parserOptions ref GitHub, if its hitting the entire repo...

If thats the case,

  • you can try and solve it by renaming tsconfig.json in the root to tsconfig.base.json and inside packages/some-package/.eslintrc.json specified parserOptions.project as path.resolve(__dirname, './tsconfig.json').

  • In my case the parserOptions.project was configured to ./tsconfig.json and I guess in this case eslint tried to run tsc on the entire repo instead of one package which affected the performance.


Second, also consider this nice explanation here with some suggestions.

Per his recommendations:

"...The underlying issue is still the overhead of the TypeScript compiler generating an AST, and the @typescript-eslint/typescript-estree work of converting this AST to an ESLint compatible AST."

His post offered some nice suggestions including caching

  • Set up .eslintignore to ignore irrelevant directories like node_modules and non-typescript files Use the --cache flag when running eslint: eslint --cache \*\*/\_.ts. Store the info about processed files in order to only operate on the changed ones. There is also a whole article on TypeScript performance which recommends:

Upvotes: 2

Related Questions