angular-cli: Slow build: loadNgStructureAsync takes 73 secs

🐞 Bug report

Command (mark with an x)

  • new
  • build
  • serve
  • test
  • e2e
  • generate
  • add
  • update
  • lint
  • xi18n
  • run
  • config
  • help
  • version
  • doc

Is this a regression?

Yes, Angular 8 was not blocked here.

Description

  • Enable benchmarking in:

…\node_modules/@ngtools\webpack\src\benchmark.js

(const benchmark = true)

Observe that there is a clear slow phase in the build:


NgccProcessor.processModule.ngcc.process+webpack-sources: 3.247ms
NgccProcessor.processModule.ngcc.process+yargs: 3.237ms
NgccProcessor.processModule.ngcc.process+source-map: 2.713ms
AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram: 13105.799ms
30% building 13/13 modules 0 activeAngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync: 73171.067ms   <=== BOOOM
AngularCompilerPlugin._make.resolveEntryModuleFromMain: 21.720ms
AngularCompilerPlugin._listLazyRoutesFromProgram.listLazyRoutes: 77.186ms
AngularCompilerPlugin._emit.ng.getNgStructuralDiagnostics: 0.024ms

🔬 Minimal Reproduction

Not currently. This is our proprietary product.

🌍 Your Environment


Angular CLI: 9.0.7
Node: 10.16.0
OS: win32 x64

Angular: 9.0.7
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... platform-server, router
Ivy Workspace: Yes

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.901.7
@angular-devkit/build-angular      0.901.7
@angular-devkit/build-ng-packagr   0.901.7
@angular-devkit/build-optimizer    0.901.7
@angular-devkit/build-webpack      0.901.7
@angular-devkit/core               9.0.7
@angular-devkit/schematics         9.0.7
@angular/cdk                       9.2.4
@angular/material                  9.2.4
@ngtools/webpack                   9.1.7
@schematics/angular                9.0.7
@schematics/update                 0.900.7
ng-packagr                         9.0.0
rxjs                               6.5.4
typescript                         3.7.5
webpack                            4.42.0

Anything else relevant?

I downgraded to 9.0.7 as hinted by https://github.com/angular/angular/issues/36272. Build time with 9.1.9 was even worse.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 21 (6 by maintainers)

Most upvoted comments

@clydin thanks for the summary of the situation.

  • Problem with dart-sass is not the performance, but rather the fact that it’s incompatible with some of the features that work with node-sass (and we are currently using). Migrating to it is a bit of an engineering project, esp. since we have multiple semi-independent projects sharing the toolchain and libs.

  • Problem with updating to Node 12 is that we are on Windows, and precompiled libsass binaries used by node-sass were not downloadable for Node 12 (as of few days ago).

These are all issues to be tackled. I’m currently thinking of

  1. reducing use of SASS by porting most components to use CSS (I kinda scripted this already, variable substitution and just calling node-sass & storing the output)

  2. Porting the stuff that needs to be in SASS to use dart-sass, and switch to that

  3. Update to node 12.

Thanks everyone for helping and listening patiently 😃. I’m closing this as resolved.

On the Sass and Node.js topic, Angular CLI 8+ no longer uses node-sass by default. Active development of Sass is now focused on dart-sass (on npm sass) and it is now the default Sass preprocessor for the Angular CLI. Although not common, if encountering inadequate performance with dart-sass, the fibers package can be used. The CLI, and in turn dart-sass, will automatically use it if it is install in the project.

Node.js 12+ is highly recommended especially if encountering memory and/or performance problems. In general, it will provide better performance and use less memory. One issue in particular with older versions of Node.js was a performance de-optimization that was triggered by certain looping constructs that contained polymorphic objects. The memory usage improvements in Node.js 12 can also provide significant overall performance benefits as well. When Node.js is close to its memory limit, the garbage collector will run repeatedly and cause less time to be available for actual code to be run.

In regards to optimizing for Sass (or any other preprocessor), one area to investigate is to ensure that excess rules are not being included in each component stylesheet. This can lead to increased build times as well as an increased final application size. In general, Sass imports should be limited to mixins and functions when possible.

@elvisbegovic Node update won’t work because I’m on Windows & node-sass doesn’t have precompiled binaries for latest node 12 (ones that would work anyway).

With disabled aot, I pay for few seconds on refresh, vs over minute on build time so that’s a tradeoff I’m currently happy to make.

With “current” aot/ivy, do you mean Angular 10 prereleases?

@vivainio Thanks for confirming. I realize now that the workload for tsc is a bit smaller when no AOT compilation has taken place, so that may be why my guess was a bit off (it was derived from createProgram + getSemanticDiagnostics + emit). Your finding is still super valuable as it indicates that SASS compilation takes approx 2/3 of analysis (loadNgStructureAsync), but this is not visible from looking at the logs.

I am not familiar with the CLI’s perf reporting logic, it might be possible to trace SASS compilation timings separately. It is currently part of loadNgStructureAsync as that is where the Angular compiler is parsing templates and reading stylesheets, therefore invoking the SASS compiler.

@JoostK tsc took only 29seconds. We have ~ 400 SASS files, which is way too much, and SASS compilation has looked like the laggy part here.

I tried replacing all the scss files with blank files, and indeed loadNgStructureAsync takes only 26 secs after that.

Would it be fair to assume then that SASS is the culprit?

If anything good comes out of this (apart from accelerating my urgency in ditching SASS for plain CSS 😉, it would be pretty great if a future update to the cli placed the blame correctly.

I would love to poke around in a reproduction. The timing logs indicate that this concerns a very large TS compilation unit, probably with hundreds of components. A reproduction would allow seeing where the AOT compiler spends its time, hopefully exposing the areas that we should focus on to improve performance.

That being said, large compilation units will result in slow builds at some point. It’s therefore not guaranteed that there any improvements possible to be made.


Chatting with Alan led us to the ability to run just ngc instead of using the Angular CLI. This will exclude Webpack and SASS compilation so it gives a better picture of how much time is spent in the Angular compiler itself (together with the TypeScript compiler). You should be able to run .\node_modules\.bin\ngc -p tsconfig.app.json or wherever the appropriate tsconfig is stored.