Click here to Skip to main content
15,881,204 members
Articles / Web Development / ASP.NET / ASP.NET Core
Tip/Trick

Lazy-loading NgModules in ASP.NET Core AngularSPA

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
20 Jul 2017CPOL2 min read 9.9K   1   2
This article shows you how configure ASP.NET Core AngularSPA starter project to serve a lazy-loaded angular module.

Angular has this cool feature of loading a module lazily. Modules that are set up to load lazily can significantly save application startup time. Lazy-load module set up is done in the application’s routing configuration section.

As the title suggests, we will be using the AngularSPA template shipped with Visual Studio 2017 Preview (2) for demonstration.

Image 1

Route that is configured to lazy-load a module sends an HTTP GET to the server which in turn returns the module in a chunk of code block. This only happens when the router is activated for the first time in application lifecycle.

Here’s how the AppModuleShared (app.module.shared.ts) is setup in the AngularSPA starter project:

JavaScript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router'; 
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
import { CounterComponent } from './components/counter/counter.component';

@NgModule({
    declarations: [
        AppComponent,
        NavMenuComponent,
        CounterComponent,
        FetchDataComponent,
        HomeComponent
    ],
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'counter', component: CounterComponent },
            { path: 'fetch-data', component: FetchDataComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
})
export class AppModuleShared {
}

Let’s assume that the CounterComponent is one of the less accessed component. It would be performance worthy to put it under a separate module and load it on demand.

Add a counter.module.ts file under the counter folder and add the following module code:

JavaScript
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { CounterComponent } from './counter.component';

@NgModule({
    imports: [
        RouterModule.forChild([{ path: '', component: CounterComponent }])
    ],
    exports: [RouterModule],
    declarations: [CounterComponent]
})

export class CounterModule { }

Notice that the module has its own route configuration. Since CounterModule is a feature module, the forChild method is used instead of forRoot for routes configuration.

Modify the app.module.shared.ts and remove the CounterComponet references from the file:

  • Remove the import statement
  • Remove component declaration from the declarations array.

Following is the modified app.module.shared.ts code:

JavaScript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router'; 
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { FetchDataComponent } from './components/fetchdata/fetchdata.component';

@NgModule({
    declarations: [
        AppComponent,
        NavMenuComponent,
        FetchDataComponent,
        HomeComponent
    ],
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        ReactiveFormsModule,
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'counter', loadChildren: 
            './components/counter/counter.module#CounterModule' },
            { path: 'fetch-data', component: FetchDataComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
})
export class AppModuleShared {
}

Now, we no longer have the component property; instead we replaced it with loadChilden. Property loadChildren takes a relative path to a module that would be lazy-loaded. Notice the module name itself is added at the end of the path string (#CounterModule). That is because CounterModule class is not the default export of the file.

The last piece of the configuration required is in the webpack.configure.js file. But first, we need to install the angular2-router-loader package.

angular2-router-loader is a Webpack loader for Angular that enables string-based module loading with the Angular Router. Use the following npm install command to install the package:

npm install  --save angular2-router-loader

Of course, change your command prompt’s directory to your application root before running the command.

Moving to configuring the angular2-router-loader package in the webpack.configure.js. In the use array, add another entry for angular-router-loader along with awesome-typescript-loader?silent=true, angular2-template-loader. The module section should now look like the following:

JavaScript
module: {
    rules: [
        { test: /\.ts$/, include: /ClientApp/, 
                use: ['awesome-typescript-loader?silent=true', 
                'angular2-template-loader', 'angular2-router-loader'] },
        { test: /\.html$/, use: 'html-loader?minimize=false' },
        { test: /\.css$/, use: ['to-string-loader', 'css-loader'] },
        { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
    ]
}

When finished, build and run the application. To make sure the CounterComponent is coming from a lazy-loaded module, open the developer console of your browser and go to the network tab. Navigating to the counter route (using the side-menu) will now load a chunk of new code via an HTTP GET request.

Image 2

Git Repository of the demo - https://github.com/fiyazbinhasan/AngularSPA

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Geek Hour
Bangladesh Bangladesh
Tech Enthusiast | Contributing Author on Microsoft Docs | Github Country Leader (C# and Typescript)

A .NET and JavaScript enthusiast. Likes to work with different technologies on different platforms. Loves the logic and structure of coding and always strives to write more elegant and efficient code. Passionate about design patterns and applying Software Engineering best practices.

I'm a young coder who did exceedingly well in my education and was offered an internship by Microsoft. I've tried a range of things and realized that what I need is a super creative challenge. I'm hungry for a real role in a challenging startup, something I can stick with for years

Comments and Discussions

 
QuestionWhich version of VS IDE you used for this Pin
Mou_kol20-Jul-17 22:44
Mou_kol20-Jul-17 22:44 
AnswerRe: Which version of VS IDE you used for this Pin
Fiyaz Hasan20-Jul-17 23:25
professionalFiyaz Hasan20-Jul-17 23:25 
VS 2017 Preview 2 (already mentioned in the second paragraph). read the official angular docs for get yourself up and running or pick any online tutorial. best of luck Thumbs Up | :thumbsup:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.