This documentation shows how Angular lazy loading can be supported using Webpack 3 for both JIT and AOT builds. The Webpack loader angular-router-loader from Brandon Roberts is used to implement this.
A big thanks to Roberto Simonetti for his help in this.
Code VS2017 angular 4.x
- Readme
- Changelog
- Hot Module Replacement
- Building production ready Angular apps with Visual Studio and ASP.NET Core
In this example, the about module will be lazy loaded when the user clicks on the about tab. The about.module.ts is the entry point for this feature. The module has its own component and routing. The app will now be setup to lazy load the AboutModule.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AboutRoutes } from './about.routes';
import { AboutComponent } from './components/about.component';
@NgModule({
imports: [
CommonModule,
AboutRoutes
],
declarations: [
AboutComponent
],
})
export class AboutModule { }
To add lazy loading to the app, the angular-router-loader npm package needs to be added to the packages.json npm file in the devDependencies.
"devDependencies": {
"@types/node": "8.0.12",
"angular2-template-loader": "^0.6.0",
"angular-router-loader": "^0.5.0",
The lazy loading routing can be added to the app.routes.ts file. The loadChildren defines the module and the class name of the module which can be lazy loaded. It is also possible to pre-load lazy load modules if required.
import { Routes, RouterModule } from '@angular/router';
export const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{
path: 'about', loadChildren: './modules/about/about.module#AboutModule',
}
];
export const AppRoutes = RouterModule.forRoot(routes);
Now the tsconfig.json for development JIT builds and the tsconfig-aot.json for AOT production builds need to be configured to load the AboutModule module.
AOT production build
The files property contains all the module entry points as well as the app entry file. The angularCompilerOptions property defines the folder where the AOT will be built into. This must match the configuration in the Webpack production config file.
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"skipLibCheck": true,
"lib": [
"es2015",
"dom"
]
},
"angularCompilerOptions": {
"genDir": "./aot",
"entryModule": "./angularApp/app/app.module#AppModule",
"skipMetadataEmit": true
},
"compileOnSave": false,
"buildOnSave": false
}
JIT development build
The modules and entry points are also defined for the JIT build.
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": true,
"skipLibCheck": true,
"lib": [
"es2015",
"dom"
],
"typeRoots": [
"./node_modules/@types/"
]
},
"exclude": [
"node_modules",
"angularApp/main-aot.ts"
],
"awesomeTypescriptLoaderOptions": {
"useWebpackText": true
},
"compileOnSave": false,
"buildOnSave": false
}
Now the webpack configuration needs to be updated for the lazy loading.
AOT production build
The webpack.prod.js file requires that the chunkFilename property is set in the output, so that webpack chunks the lazy load modules.
output: {
path: './wwwroot/',
filename: 'dist/[name].[hash].bundle.js',
chunkFilename: 'dist/[id].[hash].chunk.js',
publicPath: '/'
},
The angular-router-loader is added to the loaders. The genDir folder defined here must match the definition in tsconfig-aot.json.
module: {
rules: [
{
test: /\.ts$/,
loaders: [
'awesome-typescript-loader',
'angular-router-loader?aot=true&genDir=aot/'
]
},
JIT development build
The webpack.dev.js file requires that the chunkFilename property is set in the output, so that webpack chunks the lazy load modules.
output: {
path: './wwwroot/',
filename: 'dist/[name].bundle.js',
chunkFilename: 'dist/[id].chunk.js',
publicPath: '/'
},
The angular-router-loader is added to the loaders.
module: {
rules: [
{
test: /\.ts$/,
loaders: [
'awesome-typescript-loader',
'angular-router-loader',
'angular2-template-loader',
'source-map-loader',
'tslint-loader'
]
},
Now the application can be built using the npm build scripts and the dotnet command tool.
Open a command line in the root of the src files. Install the npm packages:
npm install
Now build the production build. The build-production does a ngc build, and then a webpack production build.
npm run build-production
You can see that Webpack creates an extra chunked file for the About Module.
Then start the application. The server is implemented using ASP.NET Core 1.1.
dotnet run
When the application is started, the AboutModule is not loaded.
When the about tab is clicked, the chunked AboutModule is loaded.
Absolutely fantastic. You could also pre-load the modules if required. See this blog.
Links:
https://github.com/brandonroberts/angular-router-loader
https://www.npmjs.com/package/angular-router-loader
https://vsavkin.com/angular-router-preloading-modules-ba3c75e424cb