Skip to content

Enabling Ivy increases bundle size #16989

@ghost

Description

🐞 Bug report

Command (mark with an x)

  • build

Description

Looks like Ivy prevents tree shaking of not referenced components/injectables. It's either a bug, or positive difference in build size can only be seen if application code actually uses all features of all dependencies, which is not realistic.

🔬 Minimal Reproduction

  1. Create a minimal application: ng new --defaults --minimal -S -s -t -g ivy-size
  2. Build with and without ivy to measure bundle sizes of an empty app:
  • With "enableIvy": false: main-es2015 is 125 kB
  • With "enableIvy": true: main-es2015 is 103 kB ✔️
  1. Install package angular2-toaster: npm i angular2-toaster
  2. Import ToasterModule in app.module.ts:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ToasterModule } from 'angular2-toaster';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    ToasterModule.forRoot(),
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
  1. Build with and without ivy again:
  • With "enableIvy": false: main-es2015 is 131 kB (increased by 6 kB)
  • With "enableIvy": true: main-es2015 is 144 kB❌(increased by 41 kB)
  1. Add <toaster-container></toaster-container> to app.component.ts
  2. Build again:
  • With "enableIvy": false: main-es2015 is 146 kB
  • With "enableIvy": true: main-es2015 is 144 kB

Sizes equalized, but now compare the final size with the size of an empty app:

  • build with "enableIvy": false increased by (146-125)=21 kB
  • build with "enableIvy": true increased by (144-103)=41 kB

I tried to make builds with command NG_BUILD_DEBUG_OPTIMIZE=minify ng build --prod and I noticed this difference in builds:
image

[ngSwitch] is used in component [toastComp], which is used by component <toaster-container>. But in <toaster-container>, component [toastComp] will not be displayed unless there's at least one element in array toasts. And to add an element I need to inject service ToasterService, which I do not do in my little app.


Here's my attempt to reproduce the issue without dependencies:

  1. Create a minimal application: ng new --defaults --minimal -S -s -t -g ivy-size
  2. Build with and without ivy to measure bundle sizes of an empty app:
  • With "enableIvy": false: main-es2015 is 125 kB
  • With "enableIvy": true: main-es2015 is 103 kB ✔️
  1. Replace app.module.ts with:
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { Component, NgModule } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<child-component *ngIf="false"></child-component>',
})
export class AppComponent {}

@Component({
  selector: 'child-component',
  template: '<input ngModel>',
})
export class ChildComponent {}

@NgModule({
  imports: [
    BrowserModule,
    CommonModule,
    FormsModule,
  ],
  declarations: [AppComponent, ChildComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

Lets build it:

  • With "enableIvy": false: main-es2015 is 158 kB
  • With "enableIvy": true: main-es2015 is 157 kB ❌

the initial positive difference in size is gone.

Lets build with NG_BUILD_DEBUG_OPTIMIZE=minify&&ng build --prod:
By looking at difference in builds I can see that not used features of CommonModule are not removed:
image
image

Same for FormsModule:
image
image

Interestingly, some not referenced classes of @angular/forms are removed: I can find RadioControlValueAccessor but not PatternValidator or NgSelectOption.

🌍 Your Environment

Angular CLI: 9.0.2
Node: 12.13.0
OS: win32 x64

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

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.900.2
@angular-devkit/build-angular     0.900.2
@angular-devkit/build-optimizer   0.900.2
@angular-devkit/build-webpack     0.900.2
@angular-devkit/core              9.0.2
@angular-devkit/schematics        9.0.2
@angular/cli                      9.0.2
@ngtools/webpack                  9.0.2
@schematics/angular               9.0.2
@schematics/update                0.900.2
rxjs                              6.5.4
typescript                        3.7.5
webpack                           4.41.2

Anything else relevant?
I tried to set "sideEffects": false, in package.json of angular2-toaster, it didn't help.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions