Repository navigation
Increased initial main.js bundle size in v9 - mainly due to @angular/material packages聽#19610
Description
馃悶 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,
Description
Our initial bundle increased after the upgrade to angular v9. Below 2 screenshots made with webpack-bundle-analyzer, both are build with the --prod tag on. The complete size of our app decreased in size, but the main bundle increased slightly.
reporting this
@filipesilva who mentioned the following
If you see your bundles increasing in size with Ivy, we want to know. Please open a new issue with a reproduction if possible. If you can鈥檛 publicly share your reproduction, consider sharing it privately instead.
In our case the initial bundle from the @angular module in angular 9.0.0 is increased by 170 kb (parsed) compared to the build size in angular 8.3.20
ANGULAR 8.3.20 bundle overview

馃敩 Minimal Reproduction
its a private repo, but can share an bitbucket account via a private message if needed
馃敟 Exception or Error
budle size difference
Angular 9:
chunk {33} polyfills-es2015.5bbe6128ce574187632a.js (polyfills) 97.3 kB [initial] [rendered]
chunk {34} polyfills-es5.7489d086305aa2ccf313.js (polyfills-es5) 188 kB [initial] [rendered]
--
chunk {18} runtime-es2015.7b3c2daa7eda967f9d4b.js (runtime) 4.55 kB [entry] [rendered]
chunk {18} runtime-es5.7b3c2daa7eda967f9d4b.js (runtime) 4.54 kB [entry] [rendered]
--
chunk {32} main-es2015.7771c8f8f77604a6a0fb.js (main) 1.13 MB [initial] [rendered]
chunk {32} main-es5.7771c8f8f77604a6a0fb.js (main) 1.32 MB [initial] [rendered]
--
chunk {35} styles.96f30aa09bf98d520a7b.css (styles) 403 kB [initial] [rendered]
Angular 8:
chunk {20} runtime-es2015.8dcc6cc63434c93fc456.js (runtime) 4.68 kB [entry] [rendered]
chunk {20} runtime-es5.8dcc6cc63434c93fc456.js (runtime) 4.67 kB [entry] [rendered]
--
chunk {40} polyfills-es2015.c6262141f4f874e78e85.js (polyfills) 98.1 kB [initial] [rendered]
chunk {41} polyfills-es5.468b140bd31c7a429390.js (polyfills-es5) 185 kB [initial] [rendered]
--
chunk {39} main-es2015.d68e6e1b9429135d5faf.js (main) 1.02 MB [initial] [rendered]
chunk {39} main-es5.d68e6e1b9429135d5faf.js (main) 1.19 MB [initial] [rendered]
--
chunk {42} styles.38056460a1b2b723be01.css (styles) 397 kB [initial] [rendered]
馃實 Your Environment
ngular CLI: 9.0.0
Node: 13.3.0
OS: darwin x64
Angular: 9.0.0
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, language-service, material, platform-browser
... platform-browser-dynamic, router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.900.0
@angular-devkit/build-angular 0.900.0
@angular-devkit/build-optimizer 0.900.0
@angular-devkit/build-webpack 0.900.0
@angular-devkit/core 9.0.0
@angular-devkit/schematics 9.0.0
@angular/flex-layout 9.0.0-beta.28
@ngtools/webpack 9.0.0
@schematics/angular 9.0.0
@schematics/update 0.900.0
rxjs 6.5.4
typescript 3.7.5
webpack 4.41.5
Anything else relevant?
Similar issues: angular/angular-cli#16989

Activity
filipesilva commentedon Feb 7, 2020
Heya, thanks for the report!
The current situations we know this might happen in are documented in https://angular.io/guide/ivy-compatibility#payload-size-debugging. Can you take a look at case 1. and 2. just in case they apply in your case?
I'd like to take a look at your project if possible. I think the most straightforward way to share it would be a private github repo (these are now free) that you invite me to. Would that work?
bri1990 commentedon Feb 7, 2020
@filipesilva
Ok done, I had a look last night at the debugging post, will have another look later today. In the meantime I gave you access to the private repo
filipesilva commentedon Feb 7, 2020
@bri1990 looking at the project at the moment. Can you tell me in which of the apps you saw the increased bundle size?
Since you have two apps and many shared libraries, I think you are suffering from case 2 in https://angular.io/guide/ivy-compatibility#payload-size-debugging. Can you try the approach described in angular/angular-cli#16799 (comment) and see if it works please?
bri1990 commentedon Feb 7, 2020
@filipesilva in the edu-app, it uses both the @education as the @banax folder (ng build --prod --project edu-app, we currently only use that one in that repo),
Regarding case 2:
I added "sideEffects": false to the main package.json (we only have one in the repo you have access), this resulted in a 0.05mb decrease in our main bundle ++
this gets us very close to the v8 build size
filipesilva commentedon Feb 7, 2020
It's not a great idea to add it in the main toplevel one, because your apps do have at least side effects in
main.ts. It's better to add it in the library roots. If the library doesn't actually have apackage.json, you can add one with just{"sideEffects": false}.filipesilva commentedon Feb 7, 2020
I tried putting these various package.json and saw a main bundle of 1.09 MB, which is still larger than the 1.02 MB with View Engine. I've got to dig a bit deeper.
bri1990 commentedon Feb 7, 2020
Hi @filipesilva, thanks for the hint! will implement it.
I hope you are able to spot the problem:)
I must admit, I expected angular v9 to reduce the initial load by quite a bit. Are we doing something wrong here? I've seen some examples elsewhere but the initial load remained the same in most cases (examples were done in 9.R.C)
In our case we have quite a large css bundle, I believe 160 kb is for theming alone (dark + normal modus), so some room to improve here.
gr
bri1990 commentedon Feb 11, 2020
@filipesilva using
"sideEffects": falseis causing some problems for us when serving the angular app after building (via nginx hosting it on google cloud platform). We are still figuring out why this is happeningperhaps it is use full information
bri1990 commentedon Feb 11, 2020
another question is, do you still need access to the repo?
filipesilva commentedon Feb 11, 2020
@bri1990 are you only seeing the problems when serving on nginx and not on
ng serve? If so, it might be a caching issue.I still need access to the repo because I wanted to find the reason for the size difference. But I also have it on disk from the initial investigation so you can remove my access and I will ask it again if relevant.
bri1990 commentedon Feb 11, 2020
Hi again @filipesilva, no it only happends on nginx, ng serve runs fine. We find it quite hard to debug, so we removed the
"sideEffects": falselines for nowWill post our findings regarding the nginx problem here
filipesilva commentedon Feb 11, 2020
Was taking a look today again, and one of the things I tried was to make builds without lazy routes. This way we can see bundle sizes without the de-optimizations that can result with lazy routes.
With Ivy the main bundle was 831296 B. With VE it was 814688 B. So even without lazy routes Ivy makes your bundle larger, which I find surprising.
I made my builds with source maps so I could use
source-map-explorerto figure out where the extra size came from. Notably, in Ivy the source maps say 715 KB come from node_modules but in VE it's only 606 KB. Within node_modules, Ivy has 526 KB from@angular/*directories while VE has only 428 KB. And of the angular packages, the Ivy bundle has 126 KB from@angular/materialwhile the VE one only has 55 KB. So looking at@angular/materialseemed promising.The Ivy sourcemaps for material looked like this:

And the VE ones:

This looks quite odd to me. The Ivy app seems to have a lot more code from Ivy.
list.jsis especially striking, since it's 29kb in Ivy but only 1kb in VE. I double checked and your app is using the correct deep imports (e.g.@angular/material/list). But I also find it weird that I can't see any.ngfactory.jsfile in these source maps, and I used to see these before.I ran
ng build edu-app --prod --verbose &> log.txtto see the verbose log for both Ive and VE. The VE log mentions the.ngfactory.jsfiles there for material so at least that confirms they were used.At this point I feel I'm kinda out of leads so I might as well just go though the verbose log to see if something catches my eyes. I've seen a bunch of these in the past so that's a reasonable enough thing to do.
I did find something odd early on:
This is the entry for the
D:/sandbox/banax_angular/node_modules/rxjs/internal/Subscriber.jsmodule. It says why this module is in the compilation, and why it's not concatenated with other modules. Module concatenation is a big part of size savings so it's important to have as little of theseModuleConcatenation bailoutas possible.I saw this
ModuleConcatenation bailout: Module is not an ECMAScript modulefor a bunch of rxjs modules. But since I know that RxJS does ship a ESM version, I find it odd. I searched the project source code forrxjs/and found a bunch ofimport { Subject } from 'rxjs/internal/Subject';and the like.Projects really shouldn't be importing from
rxjs/internalso this looks wrong. I also saw a tslint rule blacklistingrxjsand found that odd, since that is the correct way of importing things likeSubject. Maybe at some point we made projects with that lint rule and since then removed it?I replaced all
rx/internal/operators/*imports torx/operators, and all remainingrx/internal/*ones to justrxjs. I rebuilt and saw the Ivy main down to 799681 B (from 831296) and the VE one down to 783077 B (from 814688). Keep in mind these are still numbers for the app without any lazy routes. So about 31kB down in both. This wasn't the cause of the Ivy vs VE problem but it was something that was going wrong regardless.filipesilva commentedon Feb 11, 2020
Still looking at the verbose log, I remove the terser logs at the end and use VSCode's "fold all" functionality to fold log bits. It seems to recognize the boundaries pretty well.
The Ivy listing for modules in main.js looks like this:

The Ivy one:

Nothing super odd here. A bunch of little modules related to sockets and whatnot, that seem to be commonjs modules, and then a gigantic concatenated
main-edu.tsmodule. They even match line numbers. This looks right.filipesilva commentedon Feb 11, 2020
Earlier it occurred to me, and meanwhile I forgot, that that might be unused code in the app folder itself, so I also added
{"sideEffects": false}inprojects/edu-app/src/app/package.json. It can't be inprojects/edu-app/srcbecausemain.tsdoes have side effects. I tried that now, but no change. Still 799681 B.33 remaining items
devversion commentedon Jun 17, 2020
@naveedahmed1 Do you have any application we could look into? @filipesilva's investigation on list seems correct, but I'd like to double-check on other components you mentioned. e.g. tabs
naveedahmed1 commentedon Jun 17, 2020
Thanks @devversion I have added you to a private repo, will it work?
devversion commentedon Jun 17, 2020
@naveedahmed1 yeah, that will work, thanks! your help on this is much appreciated!
naveedahmed1 commentedon Jun 17, 2020
@devversion most welcome. If you receive error of No Providers for MatDialog, it would be due to this issue #19335, just add MatDialogModule to the providers and it should work.
devversion commentedon Jun 18, 2020
@naveedahmed1 I looked into it. Thanks for sharing your numbers and app. It looks like View Engine and Ivy deviate that much in your comparison because factories are directly attached to the classes, while View Engine had a separate chunk for factories (e.g.
24-es2015.x.jsin your app). if we sum these numbers up for tabs, we'll only see a size difference of ~4kb, compared to the mentioned ~29kb.Percentage-wise, these 4kb are still noticeable as that signifies a ~12% increase. The actual size differences come from factories being generated for directives. This wasn't the case in View Engine as there weren't any factories for directives. Instead, host bindings, DI etc. were directly inlined to the host factory if a directive is used. A directive factory in Ivy by average seems to be larger by around ~450b (compared to the VE inlined code). There seem to be 9 directive (base) classes in tabs, resulting in the ~4kb increase. The actual size benefit with Ivy surfaces here as multiple use of, for example
MatTabLabelis not resulting in multiple inlined factory code as with View Engine. Instead the attached factory is re-used in Ivy. That should definitely offset the 4kb, and should signify a larger size reduction in your overall application. I can definitely observe this in your application. e.g. reduction of around 15% gzipped (and lot more without gzip).naveedahmed1 commentedon Jun 20, 2020
@devversion thank you so much for your time and looking in to this, really appreciate.
devversion commentedon Jun 29, 2020
@naveedahmed1 Anytime! Thanks again for the great information/reproduction you provided! 馃帀
I'm going to close this issue as we landed our refactor changes in Angular Components. See #19576. Other than that, a slight increase in Angular Components chunks might be noticeable "at first glance", but in reality this is due to Ivy's architecture which later on results in overall size benefits (due to reduced factory code duplication etc.). Please see my comment above for a concrete example.
Also if you continue to discover any significant size impact, please create a new issue! We'd love to look into it!
angular-automatic-lock-bot commentedon Jul 30, 2020
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.