Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular Router - Let's get lazy

Angular Router - Let's get lazy

Routing in web applications is an essential concept that enables users to navigate throughout them. Angular Router is simple yet powerful for developers to use in their applications.

In this talk we will learn mechanics of Angular Router with lazy loading and pre-loading features.

Bartosz Pietrucha

June 25, 2017
Tweet

More Decks by Bartosz Pietrucha

Other Decks in Programming

Transcript

  1. Hello World Bartosz Pietrucha Full-stack software engineer Java and JavaScript

    Founder at angular-academy.com Twitter @pietrucha 2
  2. Angular Router - Let’s get lazy (loading) 3 • Angular

    Router • Lazy loading • Preloading • Router Guards
  3. Angular Router - Let’s get lazy (loading) 4 • Angular

    Router • Lazy loading • Preloading • Router Guards
  4. Angular Router 6 http://application.com/employees/1 Router configuration Root component Employees container

    Employees List Employee Details Home component Admin component Router State
  5. Angular Router 7 http://application.com/admin Router configuration Root component Employees container

    Employees List Employee Details Home component Admin component Router State
  6. Angular Router 8 Root component Employees container Home component const

    routes: Routes = [ { path: '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', component: EmployeeContainerComponent, }, { path: 'employees/:id', component: EmployeeContainerComponent }, { path: 'admin', component: AdminComponent, } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } Admin component
  7. Angular Router 9 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', component: EmployeeContainerComponent, }, { path: 'employees/:id', component: EmployeeContainerComponent }, { path: 'admin', component: AdminComponent, } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } Root component Employees container Home component Admin component
  8. Angular Router 10 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', component: EmployeeContainerComponent, }, { path: 'employees/:id', component: EmployeeContainerComponent }, { path: 'admin', component: AdminComponent, } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } Root component Employees container Home component Admin component http://application.com/employees/1
  9. Angular Router 11 Root component Employees container Home component const

    routes: Routes = [ { path: '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', component: EmployeeContainerComponent, }, { path: 'employees/:id', component: EmployeeContainerComponent }, { path: 'admin', component: AdminComponent, } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } Admin component
  10. Angular Router - Let’s get lazy (loading) 15 • Angular

    Router • Lazy loading • Preloading • Router Guards
  11. Lazy loading 17 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', loadChildren: 'app/employee/employee.module#EmployeeModule', }, { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } const routes: Routes = [ { path: '', component: EmployeeContainerComponent, }, { path: ':id', component: EmployeeContainerComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class EmployeeRoutingModule { } const routes: Routes = [ { path: '', component: AdminComponent, canActivate: [AuthService] } ]; @NgModule({ imports: [ RouterModule.forChild(routes) ] }) export class AdminModule { } Routing for root Routing for employee module Routing for admin module
  12. Lazy loading 18 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', loadChildren: 'app/employee/employee.module#EmployeeModule', }, { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } const routes: Routes = [ { path: '', component: EmployeeContainerComponent, }, { path: ':id', component: EmployeeContainerComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class EmployeeRoutingModule { } const routes: Routes = [ { path: '', component: AdminComponent, canActivate: [AuthService] } ]; @NgModule({ imports: [ RouterModule.forChild(routes) ] }) export class AdminModule { } Routing for root Routing for employee module Routing for admin module
  13. Lazy loading 19 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', loadChildren: 'app/employee/employee.module#EmployeeModule', }, { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } const routes: Routes = [ { path: '', component: EmployeeContainerComponent, }, { path: ':id', component: EmployeeContainerComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class EmployeeRoutingModule { } const routes: Routes = [ { path: '', component: AdminComponent, canActivate: [AuthService] } ]; @NgModule({ imports: [ RouterModule.forChild(routes) ] }) export class AdminModule { } Routing for root Routing for employee module Routing for admin module
  14. Lazy loading 20 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'employees', loadChildren: 'app/employee/employee.module#EmployeeModule', }, { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } const routes: Routes = [ { path: '', component: EmployeeContainerComponent, }, { path: ':id', component: EmployeeContainerComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class EmployeeRoutingModule { } const routes: Routes = [ { path: '', component: AdminComponent, canActivate: [AuthService] } ]; @NgModule({ imports: [ RouterModule.forChild(routes) ] }) export class AdminModule { } Routing for root Routing for employee module Routing for admin module
  15. Lazy loading 21 @NgModule({ declarations: [ AppComponent, ], imports: [

    BrowserModule, BrowserAnimationsModule, FormsModule, AppRoutingModule, HomeModule, // EmployeeModule, // AdminModule, SharedModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule {} Remove lazy loaded modules from imports in root module!
  16. Lazy loading 22 Bundling? Out of the box with Angular

    CLI! Angular CLI ships with webpack plugin which traverses routing configuration to create bundles matching that configuration
  17. Angular Router - Let’s get lazy (loading) 23 • Angular

    Router • Lazy loading • Preloading • Router Guards
  18. main.bundle.js Preloading 25 main.bundle.js 1. Fetch initial bundle 2. Bootstrap

    application http://application.com/ http://application.com/ Home component
  19. main.bundle.js Preloading 26 main.bundle.js 0.chunk.js 1. Fetch initial bundle 2.

    Bootstrap application 3. Fetch additional chunks in the background http://application.com/ http://application.com/ Home component http://application.com/ Home component
  20. 0.chunk.js main.bundle.js Preloading 27 main.bundle.js http://application.com/ http://application.com/ Home component http://application.com/

    Home component 0.chunk.js http://application.com/employees Employees cmp 1. Fetch initial bundle 2. Bootstrap application 3. Fetch additional chunks in the background 4. Wait for user enter new route and render immediately
  21. Preloading 28 const routes: Routes = [ { path: '',

    pathMatch: 'full', component: HomeComponent, }, { path: 'employees', loadChildren: 'app/employee/employee.module#EmployeeModule', data: { preload: true } } ]; @NgModule({ imports: [RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })], exports: [RouterModule] }) export class AppRoutingModule { }
  22. Preloading 29 const routes: Routes = [ { path: '',

    pathMatch: 'full', component: HomeComponent, }, { path: 'employees', loadChildren: 'app/employee/employee.module#EmployeeModule', data: { preload: true } } ]; @NgModule({ imports: [RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })], exports: [RouterModule] }) export class AppRoutingModule { }
  23. Preloading 30 @Injectable() export class SelectivePreloadingStrategy implements PreloadingStrategy { constructor()

    { } preload(route: Route, load: () => Observable<any>): Observable<any> { if (route.data && route.data['preload']) { console.log('Preloaded: ' + route.path); return load(); } else { return Observable.of(null); } } }
  24. Angular Router - Let’s get lazy (loading) 31 • Angular

    Router • Lazy loading • Preloading • Router Guards
  25. Router Guards 34 @Injectable() export class AuthService implements CanLoad, CanActivate

    { private _isLogged = false; constructor(private snackBar: MdSnackBar, private router: Router) { } public setLogin(isLogged: boolean) { this._isLogged = isLogged; } public isLogged(): boolean { return this._isLogged; } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):boolean|Observable<boolean>|Promise<boolean>{ this.showSnackBarIfNecessary(); return this._isLogged; } canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> { this.showSnackBarIfNecessary(); return this._isLogged; } private showSnackBarIfNecessary() { if (!this._isLogged) { this.snackBar.open('You have to be logged in!', 'OK', { duration: 3000, }); } } }
  26. Router Guards 35 @Injectable() export class AuthService implements CanLoad, CanActivate

    { private _isLogged = false; constructor(private snackBar: MdSnackBar, private router: Router) { } public setLogin(isLogged: boolean) { this._isLogged = isLogged; } public isLogged(): boolean { return this._isLogged; } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):boolean|Observable<boolean>|Promise<boolean>{ this.showSnackBarIfNecessary(); return this._isLogged; } canLoad(route: Route): boolean | Observable<boolean> | Promise<boolean> { this.showSnackBarIfNecessary(); return this._isLogged; } private showSnackBarIfNecessary() { if (!this._isLogged) { this.snackBar.open('You have to be logged in!', 'OK', { duration: 3000, }); } } }
  27. Router Guards 36 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule', canLoad: [AuthService] } ]; @NgModule({ imports: [RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })], exports: [RouterModule] }) export class AppRoutingModule { }
  28. Router Guards 37 const routes: Routes = [ { path:

    '', pathMatch: 'full', component: HomeComponent, }, { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule', canLoad: [AuthService] } ]; @NgModule({ imports: [RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })], exports: [RouterModule] }) export class AppRoutingModule { }
  29. Router Guards 38 const routes: Routes = [ { path:

    '', component: AdminComponent, canActivate: [AuthService] } ]; @NgModule({ imports: [ RouterModule.forChild(routes), CommonModule ], declarations: [AdminComponent] }) export class AdminModule { }
  30. Router Guards 39 const routes: Routes = [ { path:

    '', component: AdminComponent, canActivate: [AuthService] } ]; @NgModule({ imports: [ RouterModule.forChild(routes), CommonModule ], declarations: [AdminComponent] }) export class AdminModule { }