3

I am building an Angular 11 application and am trying to create a SharedModule. I am using lazy loading and wish to avoid loading common modules multiple times across my lazy loaded routes. I created a shared module and imported that into my AppModule. From my understanding, this shared module should be defined across all lazy-loaded module and not need to be imported anywhere else. However, in my lazy-loaded module, I get an error for not directly importing my shared module. How do I globally define my ProjectSharedModule?

I have my shared module:

@NgModule({
    declarations: [ProjectsComponent, TopNavComponent],
    imports: [
        ChartsModule,
        FormsModule,
        CommonModule,
        RouterModule,
        MatDatepickerModule,
        MatNativeDateModule,
        MatIconModule,
        MatInputModule,
        MatFormFieldModule,
        MatTooltipModule,
    ],

    exports: [
        ProjectsComponent,
        TopNavComponent,
        ChartsModule,
        FormsModule,
        CommonModule,
        MatDatepickerModule,
        MatNativeDateModule,
        MatIconModule,
        MatInputModule,
        MatFormFieldModule,
        MatTooltipModule,
    ],
})
export class ProjectSharedModule {}

Here is my AppModule

@NgModule({
    declarations: [AppComponent],
    imports: [
        ProjectSharedModule, // Shared Module should be defined globally 
        BrowserModule,
        AppRoutingModule,
        HttpClientModule,
        FeaturesModule,
        LoggerModule
    ],
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: AuthHttpInterceptor,
            multi: true,
        },
        { provide: LoggerBase, useClass: LoggerService },
    ],
    bootstrap: [AppComponent],
})
export class AppModule {}

Here is the module that gets lazy-loaded:

@NgModule({
    declarations: [
        ...
        MyComponents
        ...
    ],
    imports: [
        RouterModule,
        ProfileRoutingModule,

        // Shouldn't need these anymore
        // CommonModule,
        // FormsModule,
        // MatDatepickerModule,
        // MatNativeDateModule,
        // MatIconModule,
        // MatInputModule,
        // MatFormFieldModule,
        // MatTableModule,
        // MatTooltipModule,

        // Without including this I get an error
        // ProjectSharedModule,
    ],
})
export class ProfileModule {}

Here is the route that lazy loads the module

 {
        path: 'pr',
        loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule),
        canLoad: [AuthorizedUserGuard],
 },

Again, how do I share my ProjectSharedModule across all of my lazy loaded routes?

UPDATE

It appears that I need to import my ProjectSharedModule in my lazy loaded module. According to this article it looks like the AppModule imports the ProjectSharedModule which is cached. When the lazy loaded module then tries to import it, it is retrieved from the cache to save from duplication of a module code in runtime. Credit to this answer.

afriedman111
  • 1,925
  • 4
  • 25
  • 42

1 Answers1

1

Your SharedModule needs to be imported in every module use the shared components, no matter if it is lazy-loaded or not.

UPDATE: If you find the ProfileModule using only a few components of SharedModule, you can include them as a part of ProfileModule. The other thing you can do is dividing the SharedModule into smaller SharedModules according to their functions and import the one needed only.

So your profile.module.ts should be:

@NgModule({
    declarations: [
        ...
        MyComponents
        ...
    ],
    imports: [
        RouterModule,
        ProfileRoutingModule,
        SharedModule

        // Shouldn't need these anymore
        // CommonModule,
        // FormsModule,
        // MatDatepickerModule,
        // MatNativeDateModule,
        // MatIconModule,
        // MatInputModule,
        // MatFormFieldModule,
        // MatTableModule,
        // MatTooltipModule,

        // Without including this I get an error
        // ProjectSharedModule,
    ],
})
export class ProfileModule {}
Useme Alehosaini
  • 2,998
  • 6
  • 18
  • 26
  • Is there a way to easily detect how many times a module is loaded? – afriedman111 Nov 25 '20 at 14:29
  • Well, I afraid I did not understand your question. But the lazy loading benefit is showing in production, so itself and any imported module in it will be loaded once itself is loaded. – Useme Alehosaini Nov 25 '20 at 14:31
  • By the way, I updated my answer with options you can do to work around – Useme Alehosaini Nov 25 '20 at 14:31
  • Is there a way to profile the lazy loading? Like in Chrome Web Kit – afriedman111 Nov 25 '20 at 14:32
  • Generally, I use Chrome Network debugging to see the bundles loaded – Useme Alehosaini Nov 25 '20 at 14:36
  • Ok, I thought there might a way to detect Module loading. I don't know if Augury does or not. – afriedman111 Nov 25 '20 at 14:40
  • I would suggest you consider Preloading (Eager Lazy Loading) with Preloading strategy to use the idle time. @afriedman111 – Useme Alehosaini Nov 25 '20 at 14:41
  • If you get a chance can you look at the update to my question. It is my understanding that importing a SharedModule into AppModule caches it. Then when a module is lazy loaded, it access that module in cache which saves from duplication of a module code in runtime. – afriedman111 Nov 25 '20 at 19:02
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225126/discussion-between-u8080-and-afriedman111). – Useme Alehosaini Nov 25 '20 at 19:44
  • Hey @afriedman111 , I have checked it and checked my previous projects and resources and found them all requiring and mentioning that SharedModule should be imported everywhere needed. I just found a video that supports my argument with the title "Angular Router Lazy Loading and Shared Modules - How to Lazy-Load a Module" you may like to google it. – Useme Alehosaini Nov 25 '20 at 19:50
  • it is in AngularUniversity ytube channel – Useme Alehosaini Nov 25 '20 at 19:51
  • The lazy-loaded module creates a child injector. Any service provided via module import in a lazy-loaded module gets added to this child injector, and it will shadow the same service provided in the root injector. This means there is not a singleton but a second instance, which is not what the OP wants. See: https://angular.io/guide/ngmodule-faq#why-is-it-bad-if-a-shared-module-provides-a-service-to-a-lazy-loaded-module – chrisjsherm Jun 17 '22 at 15:55