11 min to read
Angular 14
Migración Angular 14
Buenasss como andan? Volvemos con una nueva migra de angular!! Por acá comparto la agenda de los releases y versiones oficiales.
El post de hoy va dedicado a las experiencias durante una migración específica desde un previo Angular 13 hacia Angular 14, comparto novedades, tips, errores y sus respectivos fixes para renovarnos y sacarlo con fritas!
Novedades
Repasemos algunas novedades lindas que trae esta versión.
Standalone Components
Antes de que saltes de alegría y te metas a codear standalone components, debo advertir que en ng14 esta feature está en modo DEVELOPER PREVIEW. Lo que significa que, se pueden explorar y experimentar pero a modo dev, NO están en su punto stable aún. Por lo que muy probablemente su API sufra cambios en las próximas versiones.
Ahora sí, volviendo al tema, el objetivo de los componentes standalone (independientes) de Angular es agilizar la creación de aplicaciones Angular reduciendo la necesidad de NgModules. Info completa y oficial de los standalonitos por acá
Nota: Las clases de Angular marcadas como standalone, no necesitan ser declaradas en un NgModule (de hecho el compilador de Angular reporta un error si lo intentas).
Ejemplo: Creamos Standalone component
Los componentes independientes pueden especificar sus dependencias directamente, en lugar de obtenerlas a través de NgModule. Por ejemplo, si PhotoGalleryComponent
es un componente independiente, puede importar directamente otro componente independiente ImageGridComponent
:
@Component({
standalone: true,
selector: "photo-gallery",
imports: [ImageGridComponent],
template: ` ... <image-grid [images]="imageList"></image-grid> `,
})
export class PhotoGalleryComponent {
// component logic
}
Ejemplo: Cargamos Standalone component (Lazy loading)
También, cualquier ruta puede cargar un componente independiente mediante loadComponent (en lugar de cargar un módulo):
export const ROUTES: Route[] = [
{
path: "admin",
loadComponent: () =>
import("./admin/panel.component").then((mod) => mod.AdminPanelComponent),
},
// ...
];
Pero bueno, no te quiero tentar con esta feature, mas adelante podremos dar el salto de fé y empezar a experimentarlos cuando esté en una etapa más estable.
Change detection
En Angular, la detección de cambios está muy optimizada y es muy eficaz, pero puede provocar ralentizaciones si la app ejecuta esta detección con demasiada frecuencia.
En esta guía que dejo por acá, podemos ver formas de controlar y optimizar el mecanismo de detección de cambios omitiendo partes de nuestra app y ejecutando la detección de cambios sólo cuando sea realmente necesario.
Diagnósticos
Muchas veces puede pasar que, parte de lo que codeamos resulta técnicamente válido, tanto para el compilador como para el tiempo de ejecución, SIN EMBARGO, no significa que estemos libres del mal, de bugs, por más que técnicamente esté “ok”. Es por eso, que el compilador de Angular incluye “diagnósticos extendidos” que identifica muchos de estos casos, con el fin de advertirnos sobre los posibles problemas y así poder cumplir con las mejores prácticas.
Estos son los actualmente soportados:
- NG8101 -
invalidBananaInBox
- NG8102 -
nullishCoalescingNotNullable
- NG8103 -
missingControlFlowDirective
- NG8104 -
textAttributeNotBinding
- NG8105 -
missingNgForOfLet
- NG8106 -
suffixNotSupported
- NG8107 -
optionalChainNotNullable
Para entrar en más detalles y lecturas interesantes de cada uno, comparto la docu oficial acá
Angular CLI
Algunas mejoras de Angular CLI que vale la pena destacar: ng completion Para errores tipográficos en líneas de comandos, tenemos el nuevo ng completion de la v14 que introduce el autocompletado en tiempo real.
Angular DevTools offline y en Firefox
Dejo por acá la DevTools de Firefox
Guía de migración
Bueno ahora sí, manos a la obra. Para empezar vamos a la guía oficial aquí. En este caso, viniendo de la versión 13, no necesitamos aplicar cambios en nuestro código ANTES de ejecutar el comando para poder migrar. Por lo tanto, podemos arrancar:
ng update @angular/core@14 @angular/cli@14
La mayoría de cambios requeridos los aplicamos con el comando. El resto de posibles cambios que tengamos que hacer, dependerán como siempre del proyecto en el que estemos trabajando y esta guía podría cubrir varios de esos casos.
Cambios
Para esta migración debemos tener en cuenta algunos cambios fundamentales:
- Angular ahora usa TypeScript 4.6, considerar los breaking changes acá
- Para poder migrar, asegurate de tener instalado a partir de: Node 14.15.0
- Ahora tenemos tipado estricto por defecto en los Reactive forms. Los Form models requieren un parámetro de tipo genérico. Estos formularios estrictamente tipados nos garantizan que los valores dentro de los controles de formulario, grupos y matrices son seguros en toda la superficie de la API. Esto nos permite que los formularios sean más seguros, especialmente en los casos complejos con super anidamientos y magias oscuras. Así que, para poder implementar estos cambios de forma gradual, en principio, podemos aplicar los Untyped en los formularios existentes. El comando de ng update automáticamente te “untypeará” los formgroup, formcontrols etc. Y con esto, Angular 14 viene a cerrar uno de los issues mas importantes, top top de Github: acá
- Adicionalmente, podríamos necesitar otros cambios extras, pero éstos van a depender de la app que estemos migrando, asi que comparto por acá la lista con más cambios (específicos migrando de ng13 a ng14)
Problemas durante la migración
Como en toda migración, hay cierta incertidumbre en cuanto a qué problemas podemos llegar a encontrar en el camino. En términos generales, si venis de una versión relativamente nueva como podría ser ng13, tus tests están en Jasmine , los ejecutas con Karma y nada raro, ninguna dependencia extraña o nada loco, la vida te sonreirá y migrarás sin mayores inconvenientes mas que algun que otro tema de tipado o issue dentro de todo simple de resolver. Ultimamente, los errores son mas explicitos y claros, haciendo que podamos fixearlos con mayor rapidez y sencillez.
Podría haber problemas de compatibilidad con algunas dependencias y librerías externas también, para esto habría que chequear si es posible actualizarlas o bien analizar distintas alternativas para ajustar esas dependencias.
Veamos algunos puntos y problemas comunes.
Jest
Si estás usando Jest para los unit tests, te recomiendo las siguientes versiones que van bien con ng14:
"jest": "^28.1.3",
"jest-preset-angular": "^12.2.3",
"@types/jest": "^28.1.1",
"ts-jest": "^28.0.8",
Error
En caso de que te encuentres con este error:
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import * as i0 from '@angular/core';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Solución
Es necesario que ajustes tu jest.config, con el transformIgnorePatterns
y las dependencias en cuestión:
// jest.config.js
module.exports = {
// ...other options
transformIgnorePatterns: ['node_modules/(?!@angular|@ngrx)'],
};
Teoría y explicación
Esto pasa porque por defecto, Jest NO transforma node_modules
, porque deberían ser archivos JavaScript válidos. Sin embargo, los autores de las librerías asumen que compilarás sus fuentes. Así que en estos casos, hay que decirle esto a Jest explícitamente. El código de arriba significa que @angular
, @ngrx
serán transformados, a pesar de que son node_modules
.
Ahora, si la dependencia que causa el problema es una subdependencia de un paquete node_modules
o un módulo diseñado para ser utilizado con nodeJS, podría ser necesario un custom resolver para solucionar el problema.
Dado que en estos casos, la regla de transformIgnorePatterns
, no es suficiente para agregar esas dependencias a nuestra whitelist.
Error
Entonces, si nos encontramos con problemas entre subdependencias de algun paquete, vamos a encontrarnos con un error como este:
node_modules\@angular\fire\node_modules\@firebase\firestore\dist\index.esm2017.js:12705
function (t, e) {
^^^^^^^^
SyntaxError: Function statements require a function name
Solución
Para solucionarlo, necesitamos armar un custom resolver para jest, como mencioné más arriba, y esto nos va a servir para algunas dependencias y subdependencias, como ser: Firebase, Ngrx, Rxjs, etc.
El resolver nos quedaría así:
// jest.resolver.js
module.exports = (path, options) => {
// Call the defaultResolver, so we leverage its cache, error handling, etc.
return options.defaultResolver(path, {
...options,
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
packageFilter: (pkg) => {
const pkgNamesToTarget = new Set([
"rxjs",
"@firebase/auth",
"@firebase/storage",
"@firebase/functions",
"@firebase/database",
"@firebase/auth-compat",
"@firebase/database-compat",
"@firebase/app-compat",
"@firebase/firestore",
"@firebase/firestore-compat",
"@firebase/messaging",
"@firebase/util",
"firebase",
"ngrx",
]);
if (pkgNamesToTarget.has(pkg.name)) {
// console.log('>>>', pkg.name)
delete pkg["exports"];
delete pkg["module"];
}
return pkg;
},
});
};
Para otros common issues y troubleshooting de jest-preset-angular, comparto algunas soluciones por acá
NX
Ahora si, NX es otra historia y otro mundo en la migración. Como guía para migrar desde versiones anteriores de NX a una compatible con Angular 14, comparto 2 aspectos:
- por un lado la matriz de versiones compatibles entre NX y Angular acá, para verificar qué versión necesitamos migrar
- y por otro lado, algunas alternativas para aplicar los cambios necesarios desde la generación del migrations.json (cuando aplica) para poder migrar todo nuestro NX workspace acá
NX Storybook
Con Storybook en un repo con NX, seguramente descubras que no funca nada, tanto para serve como para build del storybook de nuestra app. Muy probablemente estabas usando los builders de NX (@nrwl):
@nrwl/storybook:storybook
@nrwl/storybook:build
A partir de ahora, vamos a usar los builders puros de storybook, es decir, los mismos que usamos para servir y buildear storybook en entornos, proyectos y repositorios SIN NX:
@storybook/angular:start-storybook
@storybook/angular:build-storybook
Te dejo más detalles como guía adicional del hilo acá! y también por las dudas, la docu oficial de Storybook para Angular acá
Conclusión
Migrar de Angular 13 a Angular 14 podría volverse complejo en algunas situaciones pero tiene sus beneficios, entre los que más destacto:
- Rendimiento de alto nivel: mejoras en la velocidad y el rendimiento, haciendo nuestras apps más rápidas y fluidas.
- Migración gradual: para forms existentes en nuestra app, es posible ir migrando, tipando y experimentando a consciencia, el nuevo tipado estricto por default de los reactive forms. Para nuevos formularios, la idea es arrancar con el tipado estricto, eso sí. Acerco más info de los Typed Forms acá
- Mejoras técnicas en general, algunas que repasamos acá, otras varias que se detallan en la docu oficial, y que también nos asisten y ayudan al desarrollo e implementación de buenas prácticas.
Finalmente, comparto referencias y lecturas complementarias por acá
Happy coding!