├── .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 |
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 |
--------------------------------------------------------------------------------