angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

Some services are not tree-shaken when unused #18944

Open ranma42 opened 4 years ago

ranma42 commented 4 years ago

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

jelbourn commented 4 years ago

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.

ranma42 commented 4 years ago

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

ranma42 commented 4 years ago

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:

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.

ghostlytalamaur commented 3 years ago

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

csisy commented 1 year ago

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.

MikaStark commented 2 weeks ago

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