Components: Increased initial main.js bundle size in v9 - mainly due to @angular/material packages

Created on 7 Feb 2020  路  41Comments  路  Source: angular/components

馃悶 Bug report

Command (mark with an x)


  • [ ] new
  • [x] 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 9.0.0 bundle overview
Screenshot 2020-02-07 at 09 21 38

ANGULAR 8.3.20 bundle overview
Screenshot 2020-02-07 at 09 21 49

馃敩 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: https://github.com/angular/angular-cli/issues/16989

build in progress

Most helpful comment

@jtan80813 we're still looking into how we can address the particular problem in this issue, but things are moving along.

All 41 comments

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?

@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

@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 https://github.com/angular/angular-cli/issues/16799#issuecomment-581324624 and see if it works please?

@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),

Can you try the approach described in angular/angular-cli#16799 (comment) and see if it works please?
Ok I'm going to have a look. To explain the our repo a little you see multiple libraries but these only contain style sheets and components that are loaded into our main app

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

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 a package.json, you can add one with just {"sideEffects": false}.

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.

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

@filipesilva using "sideEffects": false is 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 happening

perhaps it is use full information

another question is, do you still need access to the repo?

@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.

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": false lines for now

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.
That is fine! was just wondering, hope you find the problem. I won't remove your access

Will post our findings regarding the nginx problem here

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-explorer to 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/material while the VE one only has 55 KB. So looking at @angular/material seemed promising.

The Ivy sourcemaps for material looked like this:
image

And the VE ones:
image

This looks quite odd to me. The Ivy app seems to have a lot more code from Ivy. list.js is 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.js file in these source maps, and I used to see these before.

I ran ng build edu-app --prod --verbose &> log.txt to see the verbose log for both Ive and VE. The VE log mentions the .ngfactory.js files 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:

 [1hPV] D:/sandbox/banax_angular/node_modules/rxjs/internal/Subscriber.js 9.17 KiB {1} [built]
     ModuleConcatenation bailout: Module is not an ECMAScript module
     cjs require ../Subscriber [JJ8B] D:/sandbox/banax_angular/node_modules/rxjs/internal/util/canReportError.js 3:33-57
     cjs require ../Subscriber [Yfti] D:/sandbox/banax_angular/node_modules/rxjs/internal/util/toSubscriber.js 3:33-57
     cjs require ./Subscriber [d4zx] D:/sandbox/banax_angular/node_modules/rxjs/internal/InnerSubscriber.js 18:33-56
     cjs require ./Subscriber [dmvN] D:/sandbox/banax_angular/node_modules/rxjs/internal/OuterSubscriber.js 18:33-56
     cjs require ../Subscriber [sGav] D:/sandbox/banax_angular/node_modules/rxjs/internal/operators/observeOn.js 18:33-57
     cjs require ./Subscriber [tkgy] D:/sandbox/banax_angular/node_modules/rxjs/internal/Subject.js 19:33-56

This is the entry for the D:/sandbox/banax_angular/node_modules/rxjs/internal/Subscriber.js module. 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 these ModuleConcatenation bailout as possible.

I saw this ModuleConcatenation bailout: Module is not an ECMAScript module for 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 for rxjs/ and found a bunch of import { Subject } from 'rxjs/internal/Subject'; and the like.

Projects really shouldn't be importing from rxjs/internal so this looks wrong. I also saw a tslint rule blacklisting rxjs and found that odd, since that is the correct way of importing things like Subject. Maybe at some point we made projects with that lint rule and since then removed it?

I replaced all rx/internal/operators/* imports to rx/operators, and all remaining rx/internal/* ones to just rxjs. 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.

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:
image

The Ivy one:
image

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.ts module. They even match line numbers. This looks right.

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} in projects/edu-app/src/app/package.json. It can't be in projects/edu-app/src because main.ts does have side effects. I tried that now, but no change. Still 799681 B.

@filipesilva are there any reports regarding the addition of {"sideEffects": false}.

We only see some js files (main, polyfills, but not the complete waterfall) served after we build the project and try to serve the compiled bundle (dist) either with nginx or http-server (the node package).

this means that our app gets stuck, we only see the splash screen in our case so we are forced to remove the {"sideEffects": false}

@bri1990 can you tell me the paths you added those package.json with {"sideEffects": false}? I can check locally if there's something weird with it.

we tried multiple ways but they all seem to have the same effect:
initially we tried:
in:
/projects/@banax/package.json
/projects/@education/package.json
/projects/edu-app/package.json

With this code (diff names)
{ "name": "banax-lib", "sideEffects": false }

than we tried to add it only in the main package.json
/package.json

Ok, some of those are the "wrong" places. "sideEffects": false means "files in this folder have no toplevel side effects". Toplevel code is code that runs when the module is imported, and toplevel side effects are effects other than declarations.

So for instance function foo(){} doesn't really have a side effect, it's just a declaration. But window.foo = function foo(){} is both a declaration and a side effect, because it's changing global state (the properties in window). Having console.log('hello') toplevel is also a side effect.

Essentially you should look at toplevel code and ask "if this code didn't run because I didn't import the file anymore, would things behave differently or break?". If the answer is yes, it's has side effects.

In Angular CLI projects, src/main.ts has two big side effects:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

Both enableProdMode() and platformBrowserDynamic().bootstrapModule(AppModule) are side effects. They do things because they were called. If you imported this file from elsewhere, this code would run and do things. If you stopped importing it, these things would not run and the application would not run anymore. So it's not correct to say /src/ or / has no side effects.

In your particular project, these are the places where you should put a package.json containing {"sideEffects": false }:

  • /projects/@banax/, because it is a shared library and you don't want all code to be retained
  • /projects/@education/, for the same reason
  • /projects/edu-app/src/app/ if you feel confident that your app files don't have any side effects it's ok to do this one,

But you can't do /projects/edu-app/ because then it would contain main.ts as well, and that file has side effects.

Looked a bit more into Materials List and why it showed such a different size between Ivy and VE. To take a good look at a good I made a debug build using NG_BUILD_DEBUG_OPTIMIZE=minify ng build edu-app --prod. We use this option to get more readable production output and see the symbol names that are in production builds.

I found MatListModule in both Ivy and VE builds and all the other modules that are also listed in node_modules/@angular/material/fesm2015/list.js. I saw that on the Ivy build there seemed to be more code for these classes than in the VE build, even including the VE ngfactory symbols.

From this I was able to make a repro:

git clone https://github.com/filipesilva/ivy-material-list-size
cd ivy-material-list-size
npm install
ng build --prod
# change tsconfig.json to have "enableIvy": false,
ng build --prod

The Ivy build has a main bundle of 232 kB, while the VE build has a main bundle of 221 kb. Still tracking down the reason for this difference in since, but having a minimal example helps a lot.

There might be other things going on besides this though.

Ok, I dissected the https://github.com/filipesilva/ivy-material-list-size example and added an explanation. Now that we know what's happening with a bit more detail we'll try to address it.


ivy-material-list-size

This repo shows a size regression with Ivy found in https://github.com/angular/angular-cli/issues/16866.

git clone https://github.com/filipesilva/ivy-material-list-size
cd ivy-material-list-size
yarn
yarn repro

The first build will use Ivy and output to dist/ivy, and the second build will use VE and output to dist/ve.

What's happening?

Given the following template:

<mat-nav-list>
  <mat-list-item>
     hello
  </mat-list-item>
</mat-nav-list>

Ivy produces a 232 kB output while VE produces a 221 kB output, resulting in a 11 kB increase.

But if you change the template to:

<mat-nav-list>
  hello
</mat-nav-list>

Ivy produces a 194 kB output while VE produces a 212 kB output, resulting in a 18 kB decrease.

You can use the command below to produce debug versions of the production bundles.
These debug versions keep the original variable names are are formatted for readability.

NG_BUILD_DEBUG_OPTIMIZE=minify ng build --prod && NG_BUILD_DEBUG_OPTIMIZE=minify ng build --configuration production,ve

The mat-list-ivy.js and mat-list-ve.js files contain contain the code from @angular/material/list that ends up in the production builds, as extracted manually from the debug builds.

The Ivy file retained the following classes:

MatListItemBase
MatNavList
MatList
MatListAvatarCssMatStyler
MatListIconCssMatStyler
MatListItem
MatListModule

The VE file retained the following classes:

MatListItemBase
list_MatNavList
list_MatList
list_MatListItem
MatListModule

Notably, the VE file does not reference either MatListAvatarCssMatStyler or MatListIconCssMatStyler.
In Ivy these two are referenced in the MatListItem factory code:

return MatListItem.\u0275fac = function(t) {
    return new (t || MatListItem)(\u0275\u0275directiveInject(ElementRef), \u0275\u0275directiveInject(ChangeDetectorRef), \u0275\u0275directiveInject(list_MatNavList, 8), \u0275\u0275directiveInject(list_MatList, 8));
}, MatListItem.\u0275cmp = \u0275\u0275defineComponent({
    type: MatListItem,
    selectors: [ [ "mat-list-item" ], [ "a", "mat-list-item", "" ], [ "button", "mat-list-item", "" ] ],
    contentQueries: function(rf, ctx, dirIndex) {
        var _t;
        1 & rf && (\u0275\u0275contentQuery(dirIndex, list_MatListAvatarCssMatStyler, !0),
        \u0275\u0275contentQuery(dirIndex, list_MatListIconCssMatStyler, !0), \u0275\u0275contentQuery(dirIndex, core_MatLine, !0)),
        2 & rf && (\u0275\u0275queryRefresh(_t = \u0275\u0275loadQuery()) && (ctx._avatar = _t.first),
        \u0275\u0275queryRefresh(_t = \u0275\u0275loadQuery()) && (ctx._icon = _t.first),
        \u0275\u0275queryRefresh(_t = \u0275\u0275loadQuery()) && (ctx._lines = _t));
    },
    hostAttrs: [ 1, "mat-list-item" ],
    hostVars: 4,
    hostBindings: function(rf, ctx) {
        2 & rf && \u0275\u0275classProp("mat-list-item-avatar", ctx._avatar || ctx._icon)("mat-list-item-with-avatar", ctx._avatar || ctx._icon);
    },
    inputs: {
        disableRipple: "disableRipple"
    },
    exportAs: [ "matListItem" ],
    features: [ \u0275\u0275InheritDefinitionFeature ],
    ngContentSelectors: list_c2,
    decls: 6,
    vars: 2,
    consts: [ [ 1, "mat-list-item-content" ], [ "mat-ripple", "", 1, "mat-list-item-ripple", 3, "matRippleTrigger", "matRippleDisabled" ], [ 1, "mat-list-text" ] ],
    template: function(rf, ctx) {
        1 & rf && (\u0275\u0275projectionDef(list_c1), \u0275\u0275elementStart(0, "div", 0),
        \u0275\u0275elementStart(1, "div", 1, void 0), \u0275\u0275elementEnd(), \u0275\u0275projection(2),
        \u0275\u0275elementStart(3, "div", 2), \u0275\u0275projection(4, 1), \u0275\u0275elementEnd(),
        \u0275\u0275projection(5, 2), \u0275\u0275elementEnd()), 2 & rf && (1, selectIndexInternal(getTView(), getLView(), getSelectedIndex() + 1, getCheckNoChangesMode()),
        \u0275\u0275property("matRippleTrigger", ctx._getHostElement())("matRippleDisabled", ctx._isRippleDisabled()));
    },
    directives: [ core_MatRipple ],
    encapsulation: 2,
    changeDetection: 0
}), MatListItem;

Additionally, Ivy contains factory code (the \u0275u0275defineComponent calls) for MatNavList, MatList, and MatListItem, but VE only contains the equivalent code (createRendererType2 calls) for MatNavList and MatListItem. Since these factories contain a large amount of css code, the bundle size increase is noticeable.

@filipesilva. Any updates on this? I have same issues with them above. My main.js is bigger but the bundle size is smaller. I have implemented the steps in https://angular.io/guide/ivy-compatibility#payload-size-debugging.

I have put {"sideEffects": false} and the bundle size became smaller but my app only shows the loading screen too so i just remove it.

Is there a problem on Angular 9 Ivy?
Hoping that this will be fixed.

Thanks a lot

@jtan80813 we're still looking into how we can address the particular problem in this issue, but things are moving along.

@filipesilva. Thats great! Pls update us here if its fixed. Thanks!

Same issue here:

  1. overall build size without Gzip: 3.48 MB with Ivy, 3.25 MB with ViewEngine

  2. MAIN bundle size without Gzip: 2.17 MB with Ivy, 1.42 MB with ViewEngine

  3. @Angular chunk size without GZip: 498 kB with Ivy, 477 kB with ViewEngine

... which is due to Ivy putting more features into synchronous chunk than ViewEngine.

Bundle with Ivy:
frontend_ivy

Bundle with ViewEngine:
frontend_classic

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
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.1
@angular-devkit/build-angular     0.900.7
@angular-devkit/build-optimizer   0.900.7
@angular-devkit/build-webpack     0.900.7
@angular-devkit/core              9.0.7
@angular-devkit/schematics        9.0.7
@angular/cdk                      9.1.3
@ngtools/webpack                  9.0.7
@schematics/angular               8.0.0
@schematics/update                0.900.7
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2

Any update on this, I think Material is the most affected:

Component   VE          IVY
tabs        16.75       >       46.27kb
select      14.14       >   24.75kb
sidenav     9.65        >   23.32kb
dialog      3.14        >   12.29kb
cdk     87      >   97kb
forms       42      >   55kb
router      68      >   71kb
platform-browser23      >   86kb


The latest version of Lighthouse (6) now shows that there's still potential of optimization in main bundle, probably due to this issue?

lighthouse-js-minify

Anyone got a chance to run Coverage Tool (https://developers.google.com/web/tools/chrome-devtools/coverage) in Chrome Dev Tools for Angular app?

After running this against my website and navigating to all sections of the website it says "32% belongs to functions that have not yet been executed" which means that of 1.10Mb main bundle, ~360kb should have been tree-shaken.

Right? or am I misinterpreting it?

Right? or am I misinterpreting it?

It's not clear how foolproof that coverage tool is. Wouldn't you need to have it navigate through and use every function in your app to be able to determine the true coverage?

Does it allow you to dig deeper to see which modules/classes/functions/etc aren't used?

I believe that most of the unused JS payload size comes from @angular/animations (~56kb) and that package is most likely retained because of this issue: https://github.com/angular/angular/issues/20002

Does it allow you to dig deeper to see which modules/classes/functions/etc aren't used?

@Splaktar Yes, it's does show which part of the code is still unused, most of it seems to be related to Angular. If you run it for a website it marks the used code with a blue line on left and unused code with red line on left.

@IgorMinar yes I think you are right. Can you please also take a look at Angular Material code especially the CDK, is the bundled code properly tree shaken?

I have the same problem reported in that issue, I opened an Isue(https://github.com/angular/components/issues/19540) in angular components but I was mentioned here.
have any bug fix predictions??

Just to clarify my last comment - just because a coverage based tool identifies code as dead, it doesn't mean that the code is eligible for tree-shaking and dead code elimination. The current state of tooling in the JavaScript ecosystem is still very primitive, and in order to remove unused code, we have to refactor the code in complex ways to enable the tooling to process is correctly.

Example:

function alwaysUsed() {
  if (isFancyApp()) {
    doSomethingRare()
  }
}

function doSomethingRare() {
  // ... lots of code here...
}

function isFancyApp() {
  //  ... some custom condition ...
}

In the code above there is no easy way for the build tooling to understand how the isFancyAppcustom condition evaluates in a particular app. And therefore all functions will always be retained and never dead-code-elimited. However a coverage based tool will correctly identify that a lot of your bundle is unused. Fixing this structural code issue is hard, but possible. It just takes a lot of time, and we've spent the last several years fixing issues like this all over Angular the Framework, Angular Material, RxJS, TypeScript, and many other libraries commonly used in Angular apps.

I'm transferring this to the components repo because most of the actions need to be taken in the @angular/material and @angular/cdk codebases (in addition to landing angular/angular#37506 in the core)

@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

Thanks @devversion I have added you to a private repo, will it work?

@naveedahmed1 yeah, that will work, thanks! your help on this is much appreciated!

@devversion most welcome. If you receive error of No Providers for MatDialog, it would be due to this issue https://github.com/angular/components/issues/19335, just add MatDialogModule to the providers and it should work.

@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.js in 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 MatTabLabel is 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).

@devversion thank you so much for your time and looking in to this, really appreciate.

@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!

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._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shlomiassaf picture shlomiassaf  路  3Comments

theunreal picture theunreal  路  3Comments

vitaly-t picture vitaly-t  路  3Comments

michaelb-01 picture michaelb-01  路  3Comments

kara picture kara  路  3Comments