Angular 12: 12 consejos de optimización

Los 12 de Angular 12

Tenemos a Angular 12 cerca, muy cerca de salir a producción y con esta nueva versión mayor es necesario preguntarse si nuestro proyecto está efectivamente optimizado.

1- Activar AOT (menor a Angular 9)

A partir de la versión 9 de Angular el AOT se incluye por defecto al compilar, para proyectos más viejos se aconseja tenerlo activado siempre al hacer un build.

2- Desuscribirse de las Observables

¿Tu aplicación de Angular tiene muchos memory leaks? Puede tener relación con no desuscribirse de las observables. Es un viejo conocido pero siempre olvidado, en el bloque ngOnDestroy incluir la observable y hacer unsuscribe() ayuda a no tener memoria reservada para ciertas acciones una vez se elimine el componente.

3- Refactorización (Componentes, funciones, métodos, etc)

Clásico de todos los lenguajes de programación, pero infaltable y, en Angular, muy útil. El hecho de trabajar con componentes nos permite reutilizarlos en cualquier parte de nuestro proyecto a fin de evitar repetir código haciendo nuestra aplicación poco mantenible. Esto aplica también para toda función repetida en nuestro componente, siempre lo ideal es generar esas funciones en servicios que se puedan consumir desde cualquier parte.

4- Estrategia de Preloading

Por defecto Angular permite aplicar dos tipos de estrategia de preloading: o todos los componentes o ninguno. Sin embargo, existen opciones de terceros mucho más optimizadas, como la renderización al hacer hover o por detección de router-link, que valen la pena probar para mejorar el rendimiento de una app.

5- Angular Universal

Utilizar renderizado del lado del servidor no solo ayuda al SEO, sino que también permite mejorar la velocidad del first byte. Para esto, en caso de tener webapps o sitios montados en Angular, es aconsejable utilizar Universal.

6- Formato de Archivos (especialmente imágenes)

Para Angular y para todo, es importante considerar utilizar formatos como WebP o, incluso mejor, AVIX y JXL; dependiendo el caso. Si nuestra app funciona con internet, mi consejo es optar por los mejores formatos disponibles y la tag PICTURE. Si es una app móvil nativa, WebP es una gran opción para mantener nuestra aplicación liviana.

7- Eliminación de archivos basura

Es un poco obvio pero muchas veces pasa que en nuestras pruebas terminamos llenando la aplicación de archivos que luego son inservibles. Es muy común con imágenes en la carpeta assets, pero tambien con archivos JavaScript que quedan sin uso perdidos por lugares. Si bien Angular está optimizado, suele agarrar todo y empaquetarlo (más si está en assets), por lo tanto es aconsejable cada tanto hacer una revisión de la "salud" de nuestros archivos, especialmente en apps nativas eso termina impactando en el peso final. Migrar todo código JavaScript a TypeScript puede ayudar considerablemente a mejorar el rendimiento de la plataforma; así como también el mantenimiento de la versión de Angular usando ng update.

8- Usar Pipes puras

Hay un dato interesante con las pipes de Angular: pueden ser puras o impuras. Es un tema para profundizar en otra entrada, pero básicamente en el caso de las puras el sistema no tiene reservado para dicha pipe un valor de inicialización. Por lo tanto las funciones de transformación se pueden compartir, esto hace que modifique el output solo si el input es distinto al valor en caché. En cambio, con las pipes impuras, cada vez que se ejecute un cambio de valor se genera en el sistema una nueva función, consumiendo poco a poco más CPU. Para asegurarnos que nuestras pipes sean puras, basta con declararlo:

@Pipe({name: 'nombrePipe', pure: true})

9- Utilizar trackBy en *ngFor

Las iteraciones siempre son eventos costosos para los navegadores, más aun la de angular que necesita recargar todo el template. Y sí, eso ocurre cuando usamos un ngFor y se nos ocurre modificar un elemento del array, debe cargarse todo nuevamente. Para esto se utiliza una operación conocida como trackBy, lo que hará que el renderizado opere solamente en los elementos modificados, haciendo que el renderizado sea más "suavizado". Para eso convertiremos nuestro ngFor:

<div *ngFor="let value of values; let i=index;">

En esto:

<div *ngFor="let value of values; let i=index;trackBy: trackByValues">

Y si, necesitamos definir la función del trackBy en nuestro TypeScript:

trackByValues(index: number, value: any) { return value.id; }

10- Cambiar la estrategia de Detección

Cada vez que cambia algo en nuestro template del componente, el sistema se ve forzado a volver a producir el renderizado. Esto está bien, pero cuando tenemos un árbol de componentes hijos exageradamente grande el chequeo de estos cambios se traduce en un costo muy elevado para la aplicación. Por tal motivo, es posible cambiar la estrategia de detección de un componente por una que no sea la existente por defecto, sino por la OnPush:

@Component({
    selector: 'component',
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: ' '
})

La implementación es sencilla, le estamos diciendo al componente que solo detecte cambios si se le aplica un nuevo valor de input. Por supuesto, sirve solo en caso de tener componentes anidados, sino no hay que utilizarlo, ya que no podremos generar detecciones de otra clase.

11- Lazy Loading

En las rutas de Angular existe una funcionalidad poco usada que es la opción de tener precargado un Componente antes de ingresar a la ruta. Esto se conoce como Lazy Loading y permite tener preparado el componente antes de pedir su renderización, lo cual ahorra tiempo. Para esto cambiaremos el atributo component por loadChildren y pediremos la carga diferencial del typescript de la siguiente manera:

const routes: Routes = [
  {
    path: 'items',
    loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  }
];

Más información: https://angular.io/guide/lazy-loading-ngmodules

12- Utilizar un presupuesto de bundle

Una forma de mejorar el peso de nuestros bundles es monitoreando sus builds; y para eso la herramienta de presupuesto (budget) de Angular puede ser de gran utilidad. Nos permitirá aplicar la opción de una adveretencia superado un peso específico y, más importante, un error al superar otro. El error impedirá que el bundle se termine de compilar, obligando a buscar las cadenas de código que están aumentando el peso.

Entradas Relacionadas

angular
Angular 12: 12 consejos de optimización
Ignacio Buioli 17 de mayo de 2021
4 min. de lectura
Compartir
Categorías
Archivar