Angular: Don’t use shared module libraries

First of all: What’s a shared module?

A Shared Module It is a module with common components, pipes, imports (external libraries) and providers. That module can be imported in other Lazy Modules. So you reuse that.

So, what’s the problem with that?

You start the project and begin with that shared module that you reuse. That’s ok at first but then the app grows, you have added more components to the shared module and that probably requires more imports…

You end with a big shared module and your Lazy loaded modules are small. Your first page of the app (the login or you index page for Angular Universal) takes a lot to load. Because it has a shared module so big, with unnecessary components and libraries.

So the next step is: Yes, you need to refactor your app.

My advice is to have the shared module small with the really basic components and libraries and that’s it.

This is my opinion, avoid shared modules. If you have in each module/component the real dependencies you will end with a faster app that you can optimize easily.

The other option it’s to have a really small parent shared module, then have others shared that you utilize in different logical parts of your app.

Real life example

Code:

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    SwiperModule,
    FlexLayoutModule,
    MatAutocompleteModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule,
    MatDatepickerModule,
    MatDialogModule,
    MatExpansionModule,
    MatGridListModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatMenuModule,
    MatMomentDateModule,
    MatPaginatorModule,
    MatProgressBarModule,
    MatProgressSpinnerModule,
    MatRadioModule,
    MatRippleModule,
    MatSelectModule,
    MatSidenavModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatSnackBarModule,
    MatSortModule,
    MatTableModule,
    MatTabsModule,
    MatToolbarModule,
    MatTooltipModule,
    MatStepperModule,
    PerfectScrollbarModule,
    PipesModule
  ],
  exports: [
    RouterModule,
    SwiperModule,
    FlexLayoutModule,
    MatAutocompleteModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule,
    MatDatepickerModule,
    MatDialogModule,
    MatExpansionModule,
    MatGridListModule,
    MatIconModule,
    MatInputModule,
    MatListModule,
    MatMenuModule,
    MatNativeDateModule,
    MatPaginatorModule,
    MatProgressBarModule,
    MatProgressSpinnerModule,
    MatRadioModule,
    MatRippleModule,
    MatSelectModule,
    MatSidenavModule,
    MatSliderModule,
    MatSlideToggleModule,
    MatSnackBarModule,
    MatSortModule,
    MatTableModule,
    MatTabsModule,
    MatToolbarModule,
    MatTooltipModule,
    MatStepperModule,
    PerfectScrollbarModule,
    PipesModule,
    RatingComponent,
    ControlsComponent,
    MainCarouselComponent,
    BrandsCarouselComponent,
    ProductsCarouselComponent,
    ProductDialogComponent,
    BannersComponent,
    BannersCardsComponent,
    CategoryListComponent,
    FilterExtraDetailComponent,
    AlertModal
  ],
  declarations: [
    RatingComponent,
    ControlsComponent,
    MainCarouselComponent,
    BrandsCarouselComponent,
    ProductsCarouselComponent,
    ProductDialogComponent,
    BannersComponent,
    BannersCardsComponent,
    CategoryListComponent,
    FilterExtraDetailComponent,
    AlertModal,
    LogoutComponent
  ],
  entryComponents:[
    ProductDialogComponent,
    AlertModal
  ]
})
export class SharedModule { 

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [
        { provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG }
        ,NotificationService
        ,AuthGuard
        ,AuthService
        ,SuperAdminGuard
        ,ConsumerGuard
		  ,{provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: {panelClass: 'mat-dialog-override'}}
		  ,{provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: {useUtc: true}}
      ]
    };
  }

}

As you can see here I have to refactor this shared module and remove a lot of components and imports. That shared module is in use in an Angular Universal site. When I finished the app I realized that this shared module was turning the first page index and all internal pages into a real slow site even if I have used Lazy loading modules everywhere (like 1 module per component)

Using a Module Size Analyser

To refactor the code and see why my “Home” page was so slow I have to use a tool called “Webpack Bundle Analyzer” to analyze each module size and dependencies.

You can refer to this guide to install it

https://dev.to/salimchemes/analyzing-angular-bundle-with-webpack-bundle-analyzer-29gp

You have to build your app for production with the flag: --stats-json

I suggest to build it with --namedChunks=true so your module build name is not replaced with a number

ng build --prod --stats-json --namedChunks=true

Then run the tool

webpack-bundle-analyzer dist/stats.json

It will open a webpage locally where you can see all modules and what each one is importing, then you can remove unnecessary dependencies in each module and optimize your app.


Profile picture


Hi, I'm Leandro Merli and this is my blog where I write about Angular, AWS, Node.JS, Serverless, Wordpress and now I'm testing and using Gatsby as SSG (static site generator), the framework I used to build this blog. :) Please follow me on medium.com or contact me in linkedin