Skip to content

Instantly share code, notes, and snippets.

@Quramy
Last active August 18, 2016 08:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Quramy/f3cdd67672eddafeb9161e2fffe43ff9 to your computer and use it in GitHub Desktop.
Save Quramy/f3cdd67672eddafeb9161e2fffe43ff9 to your computer and use it in GitHub Desktop.
ng2 lazy load routing
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { MyApp } from './my-app.component';
import { routing , appRoutingProviders } from "./app.routing";
import { TopComponent } from "./top.component";
import { AboutComponent } from "./about.component";
//import { SubModule } from "./sub/sub.module";
@NgModule({
imports: [
BrowserModule,
FormsModule,
routing,
//SubModule
],
declarations: [
MyApp,
TopComponent,
AboutComponent,
],
entryComponents: [
],
providers: [
appRoutingProviders,
],
bootstrap: [ MyApp ],
})
export class AppModule { }
import { NgModuleFactoryLoader } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { TopComponent } from "./top.component";
import { AboutComponent } from "./about.component";
import { subRoutes } from "../sub/sub.routing";
import { load , AsyncNgModuleLoader } from "../util/async-ng-module-loader";
const appRoutes: Routes = [
{path: "top", component: TopComponent},
{path: "about", component: AboutComponent },
// use loadChildren for lazy loading
{path: "sub", loadChildren: load(require("es6-promise!../sub/sub.module"), "SubModule")},
];
export const routing = RouterModule.forRoot(appRoutes, { useHash: true});
export const appRoutingProviders = [
{provide: NgModuleFactoryLoader, useClass: AsyncNgModuleLoader},
];
/*
* Based on
* https://gist.github.com/brandonroberts/02cc07face25886fe142c4dbd8da1340
*
*/
import { Injectable, NgModuleFactory, NgModuleFactoryLoader, Compiler } from '@angular/core';
class LoaderCallback {
constructor(public callback: Function, public exportName = "default") {}
}
export function load(callback: Function, exportName?: string): any {
return new LoaderCallback(callback, exportName);
};
/*
* NgModuleFactoryLoader that uses Promise to load NgModule type and then compiles them.
* @experimental
*/
@Injectable()
export class AsyncNgModuleLoader implements NgModuleFactoryLoader {
constructor(private compiler: Compiler) {}
load(modulePath: string | LoaderCallback): Promise<NgModuleFactory<any>> {
if (modulePath instanceof LoaderCallback) {
const loaderCallback = (modulePath as LoaderCallback)
return loaderCallback.callback(loaderCallback.exportName)
.then((type: any) => checkNotEmpty(type, loaderCallback.exportName))
.then((type: any) => this.compiler.compileModuleAsync(type));
}
return Promise.resolve(null);
}
}
function checkNotEmpty(value: any, exportName: string): any {
if (!value) {
throw new Error(`Cannot find export "${exportName}" in module`);
}
return value;
}

下記の変更がrouterに乗れば、NgModuleFactoryLoaderを差し替える必要は無さそう。

loadChildren は文字列またはTypeをresolveするPromise or Observable.

Promiseが与えられた場合はAoT/JITのいずれかで挙動が切り替わる模様。

  • AoTの場合、そのままPromiseで解決されたModuleが利用される
  • JITの場合、内部でcompilerが利用される

webpackのes6-promise-loaderwebpack.optimize.CommonsChunkPluginを利用するとサブモジュールをchunk.jsとして切り出すことができる。

import { NgModule } from "@angular/core";
import { subRouting } from "./sub.routing";
import { DetailComponent } from "./detail.component";
import { SummaryComponent } from "./summary.component";
@NgModule({
imports: [
subRouting,
],
declarations: [
DetailComponent,
SummaryComponent,
],
})
export class SubModule {
}
import { Routes, RouterModule } from "@angular/router";
import { DetailComponent } from "./detail.component";
import { SummaryComponent } from "./summary.component";
export const subRoutes: Routes = [
{ path: "detail", component: DetailComponent },
{ path: "summary", component: SummaryComponent },
];
export const subRouting = RouterModule.forChild(subRoutes);
const webpack = require("webpack");
const path = require("path");
module.exports = {
resolve: {
extensions: ["", ".ts", ".js"]
},
module: {
loaders: [
{test: /.ts$/, loader: "ts-loader", exclude: /node_modules/},
],
noParse: [
path.join(__dirname, "node_modules/zone.js/dist"),
path.join(__dirname, "node_modules/reflect-metadata/Reflect.js"),
]
},
entry: {
client: "./src/index"
},
output: {
path: path.resolve(__dirname, "bundle"),
publicPath: "http://localhost:3000/bundle/",
filename: "[name].js",
chunkFilename: "[id].chunk.js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ["client"]
}),
],
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment