components icon indicating copy to clipboard operation
components copied to clipboard

Some services are not tree-shaken when unused

Open ranma42 opened this issue 5 years ago • 7 comments

Reproduction

The issue cannot be shown using StackBlitz, but the repository https://github.com/ranma42/treeshake-material can be used to reproduce it.

The steps to reproduce the issue are illustrated in the commit messages of the repository. Namely:

  1. Create a new application with ng new treeshake-material with default settings (no routing, CSS style); it builds a 137 KB main.js.
  2. Install @angular/material with default settings (indigo-pink theme, no typography styles, yes to browser animations); the main.js now is 207 KB.
  3. Import several material modules in AppModule (without using any component or service); the main.js now is 271 KB.

It looks like some code is not being removed by the tree-shaking even if it is not being used.

Expected Behavior

The size of the build output does not grow unless components or services are actually used.

Actual Behavior

The size of the build output grows 2x just by installing and importing Angular Material modules, even if they are not being used.

Environment

  • Angular: 9.1.0
  • CDK/Material: 9.2.0
  • Browser(s): -
  • Operating System (e.g. Windows, macOS, Ubuntu): macOS

ranma42 avatar Mar 29 '20 17:03 ranma42

Off the top of my head, that sounds like roughly the size of the animations module, which is the only thing that the schematic adds. I'll mark this as a duplicate of https://github.com/angular/angular/issues/36306.

jelbourn avatar Mar 30 '20 23:03 jelbourn

The BrowserAnimationModule is the growth from point 1 to point 2. The growth from 2 to 3 is caused by material.

ranma42 avatar Mar 31 '20 07:03 ranma42

In particular, in addition to Overlay, which is already tracked in https://github.com/angular/components/issues/11581, it looks like several other services are not removed by tree-shaking:

  • MutationObserverFactory
  • FocusMonitor
  • ErrorStateMatcher

They are all marked providedIn: 'root', but I believe that they cannot be minified away because they are mentioned in some @NgModule.providers.

I believe the same goes for CdkTreeNodeDef which is actually a directive, even though it is listed in @NgModule.providers.

ranma42 avatar Mar 31 '20 10:03 ranma42

Additional to Overlay service, it would be great to have the MAT_MENU_SCROLL_STRATEGY token defined with providedIn: 'root'.

ghostlytalamaur avatar Apr 13 '21 16:04 ghostlytalamaur

I've been digging in the compiled code after importing a module (only the module is added to the root application's imports array, no service, no component, no directive is directly used) to find out why our modules increase the bundle size so much. And I found out that some cdk/material modules are not properly tree-shaken, as the OP mentioned (3 years ago).

So this problem is still relevant, and IMO it has a bit higher priority, especially for those who use Angular to build enterprise-level applications.

csisy avatar Aug 01 '23 10:08 csisy

If I provide some default configs and options, I see significant bundle size increase. For exemple the following code give me an extra 170kb :

// app.config.ts - providers
{
  provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
  useValue: { appearance: 'outline' },
},
{
  provide: MAT_CARD_CONFIG,
  useValue: { appearance: 'outlined' },
},
{
  provide: MAT_ICON_DEFAULT_OPTIONS,
  useValue: { fontSet: 'material-symbols-outlined' },
},
{
  provide: MAT_CHIPS_DEFAULT_OPTIONS,
  useValue: { separatorKeyCodes: [ENTER, COMMA] },
},

Using esbuild analyzer (from stats generated by ng build --stats-json), I can note the extra size came from @angular/material/xxxx which (I guess) bring the whole features but also the a11y module. For instance :

import { MAT_CHIPS_DEFAULT_OPTIONS } from '@angular/material/chips';

Gives :

image

but also :

image

Mikastark avatar Sep 02 '24 09:09 Mikastark

I'm seeing similar bundle size increases as Mikastark for the initial bundles when importing DEFAULT_OPTIONS injection tokens in our app config, which is quite unfortunate as it undoes quite a bit of our route lazy loading.

topaxi avatar Nov 28 '25 15:11 topaxi