├── .babelrc ├── .editorconfig ├── .gitignore ├── README.md ├── index.html ├── index_aot.html ├── package.json ├── src ├── index-aot.ts ├── index.ts ├── main │ ├── main-about.component.ts │ ├── main-app.component.ts │ ├── main-home.component.ts │ ├── main.module.ts │ └── main.routing.ts └── sub │ ├── sub-app.component.ts │ ├── sub-home.component.ts │ ├── sub.module.ts │ └── sub.routing.ts ├── tsconfig.json ├── webpack.config.ghpages.js ├── webpack.config.js └── webpack.config.prod.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["es2015", {"modules": false}] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | trim_trailing_whitespace = true 7 | 8 | [*.ts] 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node ### 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # node-waf configuration 19 | .lock-wscript 20 | 21 | # Compiled binary addons (http://nodejs.org/api/addons.html) 22 | build/Release 23 | 24 | # Dependency directories 25 | node_modules 26 | jspm_packages 27 | 28 | # Optional npm cache directory 29 | .npm 30 | 31 | # Optional REPL history 32 | .node_repl_history 33 | 34 | 35 | ### Typings ### 36 | ## Ignore downloaded typings 37 | typings 38 | 39 | .built/ 40 | dist/ 41 | .awcache/ 42 | src/**/*.ngfactory.ts 43 | src/**/*.ngsummary.json 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular2 Lazy Module Loading Demo 2 | 3 | It's a sample repository to explain how to lazy module loading in your Angular2 App with webpack2. 4 | 5 | This repository includes JiT(Just in Time) and AoT(Ahead of Time) demos. 6 | The AoT demo uses `ngc`([angular/compiler-cli](https://github.com/angular/angular/blob/master/modules/%40angular/compiler-cli/README.md)). 7 | 8 | ## Demonstration 9 | 10 | https://quramy.github.io/ng2-lazy-load-demo/index.html 11 | 12 | ## Build 13 | 14 | To build this in your local machine, clone this repository and exec the following: 15 | 16 | ```sh 17 | npm i 18 | npm run build 19 | npm start 20 | ``` 21 | 22 | ## How to implement async sub module loading? 23 | 24 | In Angular2 router, to load sub modules asynchronously, you can use `loadChildren`. 25 | 26 | The following code explains the steps to achieve AoT lazy loading: 27 | 28 | ```ts 29 | import { Routes, RouterModule } from "@angular/router"; 30 | import { MainHomeComponent } from "./main-home.component"; 31 | import { MainAboutComponent } from "./main-about.component"; 32 | 33 | // import { SubAppComponent } from "../sub/sub-app.component"; 34 | // import { SubHomeComponent } from "../sub/sub-home.component"; 35 | // import { SubModule } from "../sub/sub.module"; 36 | 37 | export const appRoutes: Routes = [ 38 | {path: "", component: MainHomeComponent}, 39 | {path: "about", component: MainAboutComponent }, 40 | 41 | /* 1. Simple nested routing: */ 42 | // The following configuration allows to nested routing. 43 | // But the sub components are included bundle.js so the browser loads them on init. 44 | // 45 | // { 46 | // path: "sub", 47 | // component: SubAppComponent, 48 | // children: [ 49 | // {path: "", component: SubHomeComponent} 50 | // ] 51 | // }, 52 | // 53 | 54 | /* 2. Separate sub modules and use load children callback function: */ 55 | // See the loadSubModule function in this code. 56 | // {path: "sub", loadChildren: loadSubModule}, 57 | 58 | /* 3. Auto switching module or moduleFactory with angular2-load-children-loader */ 59 | // See the loader section of webpack.config.js . 60 | {path: "sub", loadChildren: "es6-promise-loader?,[name]!../sub/sub.module#SubModule" }, 61 | 62 | ]; 63 | 64 | // export function loadSubModule(): any { 65 | // // 2-1 Naive loading sub module: 66 | // // It's synchronous loading 67 | // // return SubModule; 68 | // 69 | // // 2-2 Async module load with es6-promise-loader: 70 | // // You can create submodule's chunk with webpack es6-promise-loader. 71 | // // However you should switch the module to load with the context: 72 | // // * JiT: 73 | // // return require("es6-promise-loader!../sub/sub.module")("SubModule"); 74 | // // * AoT: 75 | // // return require("es6-promise-loader!../sub/sub.module.ngfactory")("SubModuleNgFactory"); 76 | // } 77 | 78 | export const routing = RouterModule.forRoot(appRoutes, { useHash: true}); 79 | ``` 80 | 81 | And the following part of webpack.config.js is important: 82 | 83 | ```js 84 | /* webpack.config.js */ 85 | // ... 86 | module: { 87 | rules: [ 88 | { 89 | test: /\.ts$/, 90 | loader: [ 91 | "ts-loader", 92 | "angular2-load-children-loader" // this loader replace loadChildren value to function to call require. 93 | ], 94 | } 95 | ], 96 | noParse: [ 97 | /zone\.js\/dist/, 98 | ] 99 | }, 100 | 101 | // ... 102 | 103 | output: { 104 | path: path.resolve(__dirname, "dist"), 105 | publicPath: "http://localhost:3000/dist/", 106 | filename: "[name].js", 107 | chunkFilename: "[name].chunk.js", // the chunk files are created by es6-promise-loader. 108 | }, 109 | 110 | // ... 111 | ``` 112 | 113 | Please see also [https://github.com/Quramy/angular2-load-children-loader](https://github.com/Quramy/angular2-load-children-loader). 114 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular2 Lazy Module Loading(JiT) 6 | 7 | 8 | 11 | Loading... 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /index_aot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular2 Lazy Module Loading(AoT) 6 | 7 | 8 | 11 | Loading... 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-lazy-load-demo", 3 | "version": "1.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/Quramy/ng2-lazy-load-demo.git" 9 | }, 10 | "scripts": { 11 | "clean": "rimraf dist", 12 | "clean:ngc": "rimraf src/**/*.ngfactory.ts", 13 | "ngc": "ngc", 14 | "webpack": "webpack", 15 | "watch": "webpack -w", 16 | "build": "npm run ngc && webpack --config webpack.config.prod.js", 17 | "build:ghpages": "npm run ngc && webpack --config webpack.config.ghpages.js", 18 | "start": "browser-sync start --server --files dist/*.js --files *.html --port 3000", 19 | "predeploy": "npm run clean && npm run build:ghpages && mkdir -p dist/dist && mv dist/*.js dist/dist && cp *.html dist", 20 | "deploy": "gh-pages -d dist" 21 | }, 22 | "keywords": [], 23 | "author": "Quramy", 24 | "license": "MIT", 25 | "dependencies": { 26 | "@angular/animations": "~4.0.0", 27 | "@angular/common": "~4.0.0", 28 | "@angular/compiler": "~4.0.0", 29 | "@angular/core": "~4.0.0", 30 | "@angular/forms": "~4.0.0", 31 | "@angular/http": "~4.0.0", 32 | "@angular/platform-browser": "~4.0.0", 33 | "@angular/platform-browser-dynamic": "~4.0.0", 34 | "@angular/platform-server": "~4.0.0", 35 | "@angular/router": "~4.0.0", 36 | "@angular/upgrade": "~4.0.0", 37 | "core-js": "^2.4.1", 38 | "reflect-metadata": "0.1.10", 39 | "rxjs": "^5.0.1", 40 | "tslib": "^1.6.0", 41 | "zone.js": "~0.8.4" 42 | }, 43 | "devDependencies": { 44 | "@angular/compiler-cli": "~4.0.0", 45 | "@types/core-js": "^0.9.32", 46 | "@types/node": "^6.0.38", 47 | "angular2-load-children-loader": "^0.1.0", 48 | "babel-core": "^6.14.0", 49 | "babel-loader": "^6.4.0", 50 | "babel-preset-es2015": "^6.14.0", 51 | "browser-sync": "^2.14.3", 52 | "es6-promise-loader": "^1.0.1", 53 | "gh-pages": "^0.11.0", 54 | "light-ts-loader": "^1.1.1", 55 | "rimraf": "^2.5.4", 56 | "ts-helpers": "^1.1.1", 57 | "typescript": "^2.2.1", 58 | "webpack": "^2.2.0", 59 | "webpack-merge": "^0.14.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/index-aot.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6'; 2 | import 'core-js/es7/reflect'; 3 | import 'zone.js/dist/zone'; 4 | 5 | import { platformBrowser } from '@angular/platform-browser'; 6 | import { MainModuleNgFactory } from "./main/main.module.ngfactory"; 7 | 8 | platformBrowser().bootstrapModuleFactory(MainModuleNgFactory); 9 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es6'; 2 | import 'core-js/es7/reflect'; 3 | import 'zone.js/dist/zone'; 4 | 5 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 6 | import { MainModule } from "./main/main.module"; 7 | 8 | platformBrowserDynamic().bootstrapModule(MainModule); 9 | -------------------------------------------------------------------------------- /src/main/main-about.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "main-about", 5 | template: ` 6 |
7 |

Main About Component

8 |
9 | ` 10 | }) 11 | export class MainAboutComponent { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/main-app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'my-app', 5 | template: ` 6 |
7 |

Angular2 Lazy Module Loading Demo

8 | Main Home 9 | Main About 10 | Sub 11 | 12 |
13 | `, 14 | }) 15 | export class MainAppComponent { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/main-home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "main-home", 5 | template: ` 6 |
7 |

Main Home Component

8 |
9 | ` 10 | }) 11 | export class MainHomeComponent { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/main.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { MainAppComponent } from './main-app.component'; 4 | import { routing } from "./main.routing"; 5 | import { MainHomeComponent } from "./main-home.component"; 6 | import { MainAboutComponent } from "./main-about.component"; 7 | 8 | // import { SubHomeComponent } from "../sub/sub-home.component"; 9 | // import { SubAppComponent } from "../sub/sub-app.component"; 10 | 11 | @NgModule({ 12 | imports: [ 13 | BrowserModule, 14 | routing, 15 | ], 16 | declarations: [ 17 | MainAppComponent, 18 | MainHomeComponent, 19 | MainAboutComponent, 20 | // SubAppComponent, 21 | // SubHomeComponent, 22 | ], 23 | bootstrap: [ MainAppComponent ], 24 | }) 25 | export class MainModule { } 26 | 27 | -------------------------------------------------------------------------------- /src/main/main.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from "@angular/router"; 2 | import { MainHomeComponent } from "./main-home.component"; 3 | import { MainAboutComponent } from "./main-about.component"; 4 | 5 | // import { SubAppComponent } from "../sub/sub-app.component"; 6 | // import { SubHomeComponent } from "../sub/sub-home.component"; 7 | // import { SubModule } from "../sub/sub.module"; 8 | 9 | export const appRoutes: Routes = [ 10 | {path: "", component: MainHomeComponent}, 11 | {path: "about", component: MainAboutComponent }, 12 | 13 | /* 1. Simple nested routing: */ 14 | // The following configuration allows to nested routing. 15 | // But the sub components are included bundle.js so the browser loads them on init. 16 | // 17 | // { 18 | // path: "sub", 19 | // component: SubAppComponent, 20 | // children: [ 21 | // {path: "", component: SubHomeComponent} 22 | // ] 23 | // }, 24 | // 25 | 26 | /* 2. Separate sub modules and use load children callback function: */ 27 | // See the loadSubModule function in this code. 28 | // {path: "sub", loadChildren: loadSubModule}, 29 | 30 | /* 3. Auto switching module or moduleFactory with angular2-load-children-loader */ 31 | // See the loader section of webpack.config.js . 32 | {path: "sub", loadChildren: "es6-promise-loader?,[name]!../sub/sub.module#SubModule" }, 33 | 34 | ]; 35 | 36 | // export function loadSubModule(): any { 37 | // // 2-1 Naive loading sub module: 38 | // // It's synchronous loading 39 | // // return SubModule; 40 | // 41 | // // 2-2 Async module load with es6-promise-loader: 42 | // // You can create submodule's chunk with webpack es6-promise-loader. 43 | // // However you should switch the module to load with the context: 44 | // // * JiT: 45 | // // return require("es6-promise!../sub/sub.module")("SubModule"); 46 | // // * AoT: 47 | // // return require("es6-promise!../sub/sub.module.ngfactory")("SubModuleNgFactory"); 48 | // } 49 | 50 | export const routing = RouterModule.forRoot(appRoutes, { useHash: true}); 51 | -------------------------------------------------------------------------------- /src/sub/sub-app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "sub-home", 5 | template: ` 6 |

Sub App

7 | 8 | ` 9 | }) 10 | export class SubAppComponent { 11 | } 12 | -------------------------------------------------------------------------------- /src/sub/sub-home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "sub-home", 5 | template: ` 6 |

Sub Home Component

7 | ` 8 | }) 9 | export class SubHomeComponent { 10 | } 11 | -------------------------------------------------------------------------------- /src/sub/sub.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from "@angular/core"; 2 | import { subRouting } from "./sub.routing"; 3 | import { SubAppComponent } from "./sub-app.component"; 4 | import { SubHomeComponent } from "./sub-home.component"; 5 | 6 | @NgModule({ 7 | imports: [ 8 | subRouting, 9 | ], 10 | declarations: [ 11 | SubAppComponent, 12 | SubHomeComponent, 13 | ], 14 | }) 15 | export class SubModule { 16 | } 17 | -------------------------------------------------------------------------------- /src/sub/sub.routing.ts: -------------------------------------------------------------------------------- 1 | import { Routes, RouterModule } from "@angular/router"; 2 | import { SubAppComponent } from "./sub-app.component"; 3 | import { SubHomeComponent } from "./sub-home.component"; 4 | 5 | export const subRoutes: Routes = [ 6 | { 7 | path: "", 8 | component: SubAppComponent, 9 | children: [ 10 | { path: "", component: SubHomeComponent } 11 | ] 12 | }, 13 | ]; 14 | 15 | export const subRouting = RouterModule.forChild(subRoutes); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "es2015", 4 | "target": "es2015", 5 | "noImplicitAny": true, 6 | "sourceMap": false, 7 | "outDir": ".built", 8 | "rootDir": ".", 9 | "moduleResolution": "node", 10 | "experimentalDecorators": true, 11 | "emitDecoratorMetadata": true, 12 | "types": ["node"], 13 | "importHelpers": true, 14 | "noEmitHelpers": true 15 | }, 16 | "exclude": ["node_modules", "bundle", "dist", "loaders", "src/index-aot.ts"], 17 | "angularCompilerOptions": { 18 | "genDir": ".", 19 | "debug": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /webpack.config.ghpages.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const config = require("./webpack.config.prod"); 4 | 5 | module.exports = merge({}, config, { 6 | output: { 7 | publicPath: "https://quramy.github.io/ng2-lazy-load-demo/dist/" 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | 4 | module.exports = { 5 | resolve: { 6 | extensions: [".js", ".ts"], 7 | }, 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.ts$/, 12 | loader: [ 13 | "babel-loader", 14 | "angular2-load-children-loader", 15 | "light-ts-loader" 16 | ], 17 | } 18 | ], 19 | noParse: [ 20 | /zone\.js\/dist/, 21 | ] 22 | }, 23 | entry: { 24 | bundle: "./src/index", 25 | bundle_aot: "./src/index-aot" 26 | }, 27 | output: { 28 | path: path.resolve(__dirname, "dist"), 29 | publicPath: "http://localhost:3000/dist/", 30 | filename: "[name].js", 31 | chunkFilename: "[name].chunk.js", 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const merge = require("webpack-merge"); 3 | const config = require("./webpack.config"); 4 | 5 | module.exports = merge({}, config, { 6 | plugins: [ 7 | new webpack.LoaderOptionsPlugin({ 8 | minimize: true, 9 | debug: false 10 | }), 11 | new webpack.optimize.UglifyJsPlugin({ 12 | compress: { 13 | warnings: false 14 | }, 15 | output: { 16 | comments: false 17 | }, 18 | sourceMap: true 19 | }) 20 | ], 21 | devtool: "sourcemap", 22 | }); 23 | --------------------------------------------------------------------------------