Angular es mi framework favorito por el orden que te mantiene a la hora de programar, y esto se debe también a TypeScript, el superset de Javascript, en este post hablo sobre el .
Una de las buenas prácticas que nos provee este gran framework es la carga de módulos mediante Lazy Loading.
Pero antes de continuar, ¿qué es eso de “Lazy Loading”?
Lazy Load es un patrón de diseño que consiste en retrasar la carga o inicialización de un objeto hasta el momento de su utilización.
Esto significa que obtiene los datos o procesa los objetos solamente cuando se necesitan, no antes. Esto se debe a que si se obtiene todos los datos antes de usarlos puede tener como resultado una mala experiencia de usuario, esto es muy importante del lado del frontend, porque sabemos que toda la carga es del lado del cliente, modularizar y diferir cargas ayuda a la aplicación a enfocarse en un código en especifico.
Ahora si hablemos de como aplicar este patrón en la carga de módulos en Angular.
Vamos a crear una aplicación con dos componentes (Battle y Search) que serán llamados por un menú, donde hay un componente llamado (Admin) que es nuestra base.
Una mala práctica que aplicamos a la hora de empezar a programar con este framework es que por cada componente que creamos se carga en el app.module.ts y se llama a cada componente en el app-routing.module.ts
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AdminComponent } from './modules/admin/admin.component';
import { BattleComponent } from './modules/battle/battle.component';
import { SearchComponent } from './modules/search/search.component';@NgModule({
declarations: [
AppComponent,
AdminComponent,
BattleComponent,
SearchComponent
], imports: [
BrowserModule
], providers: [], bootstrap: [AppComponent]})export class AppModule { }
app-routing.module.ts
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{
path: 'battle',
component: BattleComponent
},
{
path: 'search',
component: SearchComponent
}
]
},
{ path: '**', redirectTo: 'battle' },
];
Es una mala práctica, porque por ejemplo, si vamos a la ruta Battle nos carga todos los componentes que creamos y en una aplicación más grande vamos a ver que el rendimiento es super malo.
La mejor forma de revertir esto es aplicando Lazy Loading, para esto debemos crear un module y un router.module por cada componente que queremos utilizar, lo podemos hacer con el Angular Cli.
$ ng g m modules/battle --routing
$ ng g c modules/battle$ ng g m modules/search --routing
$ ng g c modules/search
- ng: Angular Cli
- g: Generate
- m: Modulo
- c: Componente
Si nos vamos a la carpeta modules/battle podemos observar los siguientes archivos que se crearon
|____battle-routing.module.ts
|____battle.component.css
|____battle.component.html
|____battle.component.spec.ts
|____battle.component.ts
|____battle.module.ts
Vamos a modificar el battle-routing.module.ts y quedaría de la siguiente manera:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BattleComponent } from './battle.component';const routes: Routes = [
{
path: '',
component: BattleComponent
}
];@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})export class BattleRoutingModule { }
Lo mismo hacemos con el search-routing.module, estos routings serán importados desde su respectivo module.
Ahora vamos a llamar estos modules desde el app-routing.module.ts
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{
path: 'battle',
loadChildren: './modules/battle/battle.module#BattleModule'
},
{
path: 'search',
loadChildren: './modules/search/search.module#SearchModule'
}
]
},
{ path: '**', redirectTo: 'battle' },
];
De esta forma nuestro app.module.ts queda más limpio y los demás componentes serán llamados a medida que serán solicitados por sus respectivas rutas.
Cuando corremos el ng build vemos que no se crea un solo archivo .js donde está nuestra aplicación, sino el crea por cada módulo un .js (Ver imagen)
En este caso vemos que los .js que empiezan por 4 y 5 son nuestros módulos Battle y Search.
Y así correría en nuestro server:
Otro caso de uso, podría ser que dentro de nuestro componente Battle tuviese más componentes hijos y rutas hijas, en este caso el battle-routing.module.ts quedaría de la siguiente manera.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BattleComponent } from './battle.component';const routes: Routes = [
{
path: '',
component: BattleComponent,
children: [
{
path: '',
redirectTo: 'battle-child',
pathMatch: 'full'
},
{
path: 'battle-child',
loadChildren: './modules/battle/child/child.module#ChildModule'
},
{
path: 'battle-child-two',
loadChildren: './modules/battle/child-two/child-two.module#ChildTwoModule'
}
] }
];@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})export class BattleRoutingModule { }
Como frontend developers tenemos muchas responsabilidades, y más allá de que la aplicación sea brutal, lo mejor del mundo, si tarda mucho en cargar, el usuario final se nos va y adios todo el trabajo.
Lazy Loading nos ayuda a que nuestro usuario final disfrute de nuestra app :)
PD: Pronto verán de que va la aplicación GithubBattle, hasta la próxima.