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

Angular Router - Let's get lazy

Bartosz Pietrucha
September 22, 2017
220

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

September 22, 2017
Tweet

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 @pietrucha
  3. Angular Router - Let’s get lazy (loading) 4 • Angular

    Router • Lazy loading • Preloading • Router Guards @pietrucha
  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 @pietrucha
  5. Angular Router 7 http://application.com/admin Router configuration Root component Employees container

    Employees List Employee Details Home component Admin component Router State @pietrucha
  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 @pietrucha
  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 @pietrucha
  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 @pietrucha
  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 @pietrucha
  10. Angular Router 13 constructor(private router: Router) { } this.router.navigate(['/employees/', id]);

    <button class="button" [routerLink]="['/admin']">Admin</button> @pietrucha
  11. Angular Router - Let’s get lazy (loading) 15 • Angular

    Router • Lazy loading • Preloading • Router Guards @pietrucha
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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! @pietrucha
  17. 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 @pietrucha
  18. Angular Router - Let’s get lazy (loading) 23 • Angular

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

    application http://application.com/ http://application.com/ Home component
  20. 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
  21. 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
  22. 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 { } @pietrucha
  23. 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 { } @pietrucha
  24. 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); } } } @pietrucha
  25. Angular Router - Let’s get lazy (loading) 31 • Angular

    Router • Lazy loading • Preloading • Router Guards @pietrucha
  26. 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, }); } } } @pietrucha
  27. 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, }); } } } @pietrucha
  28. 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 { } @pietrucha
  29. 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 { } @pietrucha
  30. Router Guards 38 const routes: Routes = [ { path:

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

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