Angular-cli: Angular 10 - Build prod produces huge file

Created on 8 Jul 2020  Β·  10Comments  Β·  Source: angular/angular-cli

🐞 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, this is not present in the last 9.x release

Description

After upgrading from angular 9 to angular 10, the main.js bundle increased in size from ~300KB to ~3MB.
The issue occurs only when using ng build --prod. On non-prod build the bundle size is normal.

πŸ”¬ Minimal Reproduction

πŸ”₯ Exception or Error

Angular 9:

chunk {11} main-es2015.a303ff070841eb667b29.js (main) 264 kB [initial] [rendered]
chunk {11} main-es5.a303ff070841eb667b29.js (main) 299 kB [initial] [rendered]
chunk {21} vendor-es2015.20f209356a2110a7a679.js (vendor) 787 kB [initial] [rendered]
chunk {21} vendor-es5.20f209356a2110a7a679.js (vendor) 913 kB [initial] [rendered]

Angular 10:

chunk {11} main-es2015.ec0844ff677be2743be8.js (main) 2.85 MB [initial] [rendered]
chunk {11} main-es5.ec0844ff677be2743be8.js (main) 2.88 MB [initial] [rendered]
chunk {21} vendor-es2015.51c07ad1ca77672d6e91.js (vendor) 784 kB [initial] [rendered]
chunk {21} vendor-es5.51c07ad1ca77672d6e91.js (vendor) 910 kB [initial] [rendered]

WARNING in budgets: Exceeded maximum budget for initial-es2015. Budget 2 MB was not met by 1.8 MB with a total of 3.8 MB.

WARNING in budgets: Exceeded maximum budget for initial-es5. Budget 2 MB was not met by 2.04 MB with a total of 4.04 MB.

🌍 Your Environment

Angular CLI: 10.0.1
Node: 12.10.0
OS: linux x64

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

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.1000.1
@angular-devkit/build-angular      0.1000.1
@angular-devkit/build-optimizer    0.1000.1
@angular-devkit/build-webpack      0.1000.1
@angular-devkit/core               10.0.1
@angular-devkit/schematics         10.0.1
@angular/cdk                       10.0.1
@angular/cli                       10.0.1
@angular/material                  10.0.1
@angular/material-moment-adapter   10.0.1
@ngtools/webpack                   10.0.1
@schematics/angular                10.0.1
@schematics/update                 0.1000.1
rxjs                               6.6.0
typescript                         3.9.6
webpack                            4.43.0

Anything else relevant?


Normal build:
Screenshot from 2020-07-08 10-18-42

Prod build:
Screenshot from 2020-07-08 10-54-15

low investigation memorperformance

Most helpful comment

Thanks @LickIt, I’ll try to take a look tomorrow.

All 10 comments

Hi @LickIt,

Is is possible to share a reproduction even privately? Have you analyzed the bundle to determine what is causing the addition ~2.5mb Increase?

Can you also try to run ng build -β€”prod -β€”no-progress β€”-verbose and copy the output to a file and share it?

Here are some findings.

Attaching the verbose log as well - ng10_verbose.log

I have been trying to isolate the issue all day with no luck.
I will try to minimize the code so I can share it privately.

The main.js file contains mostly duplicated code fragments. Since it's minified I can't really pin-point where they come from.
Screenshot from 2020-07-08 12-42-44
This code fragment seems to be duplicated 190 times which consumes ~80% of the whole file.

A bit more context.
This api module contains a bunch of models (dto interfaces):

import * as Enums from '../enums';

export interface ApiConfirmsReportParameters {
    date?: string;
    regenerate?: boolean;
    reportType?: Enums.WorkflowReportType;
    runMode?: Enums.RunMode;
    showShares?: Enums.YesNo;
}

that use enums, defined in a enums.ts file:

export interface AccountBasics {
    label: string;
    value: number;
}
export const AccountBasics = {
    US_GAAP: {"value":0,"label":"US GAAP"} as AccountBasics,
    IFRS: {"value":1,"label":"IFRS"} as AccountBasics,
};

...

Each of the 190 duplicated code fragments defines all of the enumeration types.
So basically 190 times by 170 enumeration definitions and it fills the extra space in the file.
What I'm trying to isolate is where this number 190 comes from and what it's related to. The models are 189 in total which is suspiciously close but most of them don't use the enums at all.

@LickIt, we'd require a reproduction to determine what's the cause of this. Thanks.

@alan-agius4 I have managed to cut down a lot of the code and reproduce it in a new project.
I have created a private repo and given you access: https://github.com/LickIt/bundle-size-bug

master branch is angular 9:

chunk {1} main-es2015.47dba6a069d681bdc354.js (main) 28 kB [initial] [rendered]
chunk {1} main-es5.47dba6a069d681bdc354.js (main) 28.1 kB [initial] [rendered]

angular-10 branch is angular 10 where the issue is present:

chunk {1} main-es2015.9f523cb0fd6d8bda545b.js (main) 104 kB [initial] [rendered]
chunk {1} main-es5.9f523cb0fd6d8bda545b.js (main) 104 kB [initial] [rendered]

You can check the app.component.ts where adding more enumerations causes the file to grow bigger with each one.

Thanks @LickIt, I’ll try to take a look tomorrow.

Hi @LickIt, just a quick update as I am still investigating the issue.

The size regressions seems to be caused by a change in TypeScript 3.9. Previously in TypeScript 3.8 the barrel file app/api/index.js content was:

export * from './api.module';
export * from './enums';

While with 3.9, this contains:

export * from './models/models';
export * from './api.module';
export * from './enums';

Another distinctive difference is that in models/models.js which is another barrel file and exports a lot of interfaces which in TS 3.8 the emitted file was empty while in TS 3.9 it contains a a lot of export * for the empty interface files:

export * from './aMLDocumentTypeDateDTO';
...

This is causing optimisation bailouts.

I'll continue looking at this later on and keep updating this issue.

Hi again, so I discussed this with the rest of the team and it seems that the change in TypeScript is intended as it's more correct. See: https://github.com/microsoft/TypeScript/issues/37123

As a workaround you can add a package.json under the api folder with the below contents:

{
    "sideEffects": false
}

See https://angular.io/guide/strict-mode#non-local-side-effects-in-applications for more info.

Barrel files are known to cause certain optimization bailouts and one must be very careful when using them, see also: https://github.com/angular/angular-cli/issues/16799

Thank you @alan-agius4 for the quick response!
The workaround seems to be working. Back to normal bundle size. Actually even smaller than before :)

Would you recommend getting rid of the barrel files altogether?

In general I am not a big fan of barrel files, especially nested once, but that is my personal preference.

If I do need to use barrels, I’d avoid using import * or export * as these will cause optimization bailout.

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