angular2路由懒加载

2017-12-26

懒加载的目的

当使用ng-cli发布angular2项目时,我们的代码一般会打包到一个名为main.***.bundle.js的文件中,里面包含了所有我们自己开发的模块的代码以及我们项目中所依赖的第三方模块的代码。随着我们的项目越来越复杂,我们自己开发的模块会越来越多,第三方依赖也越来越多,打包生成的main.***.bundle.js文件会越来越大,这会使我们的项目首次加载的时间越来越长。

这个时候我们可以使用路由懒加载来优化我们的项目。其思路是:我们将一些不常用的模块不打包到main.***.bundle.js中,只有当用户主动访问该模块时,才去请求该模块的代码,从而减少main.***.bundle.js的大小,加快加载首页的时间。

懒加载配置

1. 将子路由模块messagepath设为''

old:

const routes:Route[] = [
    {
        path: 'message',
        pathMatch: 'full',
        component: MessageListComponent,
        canActivate: [AuthService],
        resolve: {
            message: MessageService
        }
    }
];

new:

const routes:Route[] = [
    {
        path: '',
        ...
    }
];

注意懒加载的路由模块注册路由时需使用forChild

2. 在主路由模块中添加一个pathmessage的路由,并将loadChildren设为MessageModule所在的路径。

const routes:Route[] = [
    {
        path: 'message',
        loadChildren: 'app/modules/message/message.module#MessageModule'
    },
    ...
]

3. 在AppModule中移除所有MessageModule的引用。

4. 观察ng serve控制台,我们会发现新生成了一个名为message.module.chunk.js的文件。

懒加载策略

我们可以在主路由模块中使用preloadingStrategy配置懒加载策略。

@NgModule({
    imports:[
        RouterModule.forRoot(routes, {
            useHash: true,
            preloadingStrategy: PreloadAllModules
        })
    ],
    exports:[
        RouterModule
    ]
})

angular2有两种懒加载策略:

  • NoPreloading, 默认值,不自动加载配置了懒加载的模块,只有当用户主动访问该模块时,才加载该模块的文件。
  • PreloadAllModules, 在主模块加载成功后,立马加载所有的配置了懒加载的模块。

canLoad能阻止模块的懒加载,其优先级高于canActivate

自定义路由加载策略

angular2内置的两种懒加载策略,要么在主模块加载后不加载所有模块,要么在主模块加载后加载所有模块,通过自定义懒加载策略我们可以实现在主模块加载后,根据我们的配置项加载指定的模块。

1. 给需要懒加载的模块,添加一个特别的属性。

这里我们在data上添加一个preload属性,主模块加载后,我们希望只加载preloadtrue的模块。

const routes:Route[] = [
    {
        path: 'message',
        loadChildren: 'app/modules/message/message.module#MessageModule',
        data: {
            preload:true
        }
    },
    {
        path: 'user/:loginname',
        loadChildren: 'app/modules/user/user.module#UserModule'
    },
    ...
]

2. 新建一个文件实现PreloadingStrategy接口

实现PreloadingStrategy接口,我们需要实现preload函数,preload函数有两个参数,一个是当前路由route,一个是load函数,我们可以从route上取得自定义的数据,然后判断是否需要加载,需要加载只需调用load函数即可,如果不需要加载,我们需要返回一个空的Observable对象。

import 'rxjs/add/observable/of';
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class SelectivePreloadingStrategy implements PreloadingStrategy {
    preloadedModules: string[] = [];

    preload(route: Route, load: () => Observable<any>): Observable<any> {
        if (route.data && route.data['preload']) {
            // add the route path to the preloaded module array
            this.preloadedModules.push(route.path);

            // log the route path to the console
            console.log('Preloaded: ' + route.path);

            return load();
        } else {
            return Observable.of(null);
        }
    }
}

3. 在主模块的providers中注册SelectivePreloadingStrategy服务,然后将主路由模块中的preloadingStrategy的值设为SelectivePreloadingStrategy

providers: [
    SelectivePreloadingStrategy,
    ...
  ],
imports:[
    RouterModule.forRoot(routes, {
        useHash: true,
        preloadingStrategy: SelectivePreloadingStrategy
    })
],