Angular 11 build doesn't generate enough Lazy chunk files

Viewed 1524

I am trying to lazy load my modules from different libraries. I have two libraries in node_modules and the main app uses them to lazily load the modules. Here is my app-routing-module

const routes: Routes = [
  {
    path: 'admin/b',
    loadChildren: () => import('lib2-web').then(m => m.BModule)
  }, {
    path: 'admin/e',
    loadChildren: () => import('lib2-web').then(m => m.EModule)
  }, {
    path: 'admin/u',
    loadChildren: () => import('lib1-web').then(m => m.UModule)
  }, {
    path: 'admin/r',
    loadChildren: () => import('lib1-web').then(m => m.RModule)
  }, {
    path: 'admin/c',
    loadChildren: () => import('lib1-web').then(m => m.CModule)
  }, {
    path: 'admin/i',
    loadChildren: () => import('lib1-web').then(m => m.IModule)
  }, {
    path: 'admin/w',
    loadChildren: () => import('lib1-web').then(m => m.WModule)
  }, {
    path: 'admin/c/:id/r',
    loadChildren: () => import('./ru').then(m => m.RCModule)
  }, {
    path: 'admin/c',
    loadChildren: () => import('lib2-web').then(m => m.RUModule)
  }, {
    path: 'admin/r',
    loadChildren: () => import('./re').then(m => m.REModule)
  }, {
    path: 'data/t',
    loadChildren: () => import('./t').then(m => m.TModule)
  }, {
    path: 'a',
    loadChildren: () => import('lib1-web').then(m => m.AModule)
  }, {
    path: 'admin',
    loadChildren: () => import('lib1-web').then(m => m.LModule)
  }, {
    path: 'data',
    loadChildren: () => import('lib1-web').then(m => m.LModule)
  }
  ];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {
}

When I build this I get output like this

Initial Chunk Files | Names         |      Size
main.js             | main          | 453.40 kB
scripts.js          | scripts       | 229.55 kB
styles.css          | styles        | 160.45 kB
polyfills.js        | polyfills     |  36.39 kB
runtime.js          | runtime       |   2.20 kB

                    | Initial Total | 882.00 kB

Lazy Chunk Files    | Names         |      Size
0.js                | -             |  40.10 kB
6.js                | -             |   7.07 kB
5.js                | -             |   5.24 kB
7.js                | -             |   2.20 kB

I am expecting to have 14 lazy chunk files but instead I have 4 files, [6.js, 5.js and 7.js] are the ones that are in the main application and the other one (0.js) is lib2-web. lib1-web doesn't event get into the lazy chunk files.. its in the main.js. I think that's because I import modules from lib1-web inside the main application but I need to use those modules in everywhere of the application.

This is how I import modules from lib1-web in lib2-web and main app.

import { DataService, Page, Message } from "lib1-web";

When I remove these imports in the main app, I get the lib1-web inside the lazy-chunk files.

Initial Chunk Files | Names         |      Size
main.js             | main          | 285.19 kB
scripts.js          | scripts       | 229.55 kB
styles.css          | styles        | 160.45 kB
polyfills.js        | polyfills     |  36.39 kB
runtime.js          | runtime       |   2.20 kB

                    | Initial Total | 713.79 kB

Lazy Chunk Files    | Names         |      Size
1.js                | -             | 154.65 kB -- lib1-web
2.js                | -             |  40.59 kB
0.js                | -             |  16.54 kB
7.js                | -             |   3.52 kB
8.js                | -             |   1.75 kB
9.js                | -             |   1.57 kB

I don't need to have the utility modules to be lazily loading since they are used in everywhere of the application. The ideal scenario for me to have utility modules in the main.js and lazily load other modules. How can I achieve that? Importing it like this might help import {DataService} from 'lib1-web/utility'

Even I achieve the expected scenario like that, How can I have lazy chunk files for each of the module not the entire library?

1 Answers

One way to lazy load angular library is to wrapped it in a module:

Luckily, there is a way where we can create extremely minimal wrapper modules locally inside of the consumer application codebase which will import the module from the library in a standard way using import { SomeLibModule } from '@my-org/some-lib' and then import that module inside of the @NgModule decorators imports: [SomeLibModule] array as show below.

This is it! A tiny wrapper module that enables us to integrate our library as a lazy loaded route into our application! Amazing stuff!

The last step Once we have our wrapper module ready we can reference it in the route using a standard relative path because the wrapped module belongs to the application project itself.

Our lazy route now references local wrapper module so it will work as expected!

For newer version of angular you set it this way:

const routes: Routes = [
  {
    path: 'admin/b',
    loadChildren: () => import('./some-lib-wrapper-module').then(m => m.SomeLibWrapperModule)
  }
  ];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {
}

For more information check here and here.

Related