DEV Community

Cover image for Angular 15 ya disponible
Antonio Cardenas for Macao And Friends Blog

Posted on

Angular 15 ya disponible

Traducción del artículo del Angular Blog:

por: Minko Gechev

Durante el año pasado, Angular a pasado por muchos cambios como ser el deprecar el soporte al compilador legacy o el pipeline de renderizado, lo que permitió el desarrollo de una serie de mejoras en la experiencia del desarrollador en los últimos meses. Angular v15 es la culminación de esto con docenas de mejoras que conducen a una mejor experiencia y rendimiento del desarrollador.

¡Las API independientes ahora son estables!

En la v14 presentamos nuevas API independientes que permiten a los desarrolladores crear aplicaciones sin usar NgModules. Nos complace compartir que estas API se graduaron de la versión preliminar para desarrolladores y ahora forman parte de la superficie API estable. De aquí en adelante los evolucionaremos gradualmente siguiendo el versionado semántico.

Como parte de asegurarnos de que las API independientes estuvieran listas para usarse de manera estable, nos aseguramos de que los componentes independientes funcionen en Angular, y ahora funcionan completamente en HttpClient, Angular Elements, el router y más.

Las API independientes le permiten arrancar una aplicación usando un solo componente:

import {bootstrapApplication} from  '@angular/platform-browser' ; 
import { ImageGridComponent } from './image-grid' ; 

@Component ({ 
  standalone : true , 
  selector : 'photo-gallery' , 
  imports : [ ImageGridComponent ], 
  template : ` 
    … <image-grid [images]="imageList"></image-grid> 
  ` , 
}) 
export  class  PhotoGalleryComponent { 
  // lógica del componente
 } 
bootstrapApplication(PhotoAppComponent);
Enter fullscreen mode Exit fullscreen mode

APIs independientes de routing y HttpClient al cual se le puede aplicar tree-shaking

¡Puede crear una aplicación de múltiples rutas utilizando las nuevas API independientes del enrutador! Para declarar la ruta raíz puedes usar lo siguiente:

export const appRoutes: Routes = [{
  path: 'lazy',
  loadChildren: () => import('./lazy/lazy.routes')
    .then(routes => routes.lazyRoutes)
}];
Enter fullscreen mode Exit fullscreen mode

Donde lazyRoutes se declaran en:

import {Routes} from '@angular/router';

import {LazyComponent} from './lazy.component';

export const lazyRoutes: Routes = [{path: '', component: LazyComponent}];
Enter fullscreen mode Exit fullscreen mode

y finalmente, registrar el appRoutes en la bootstrapApplication llamada:

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(appRoutes)
  ]
});
Enter fullscreen mode Exit fullscreen mode

¡Otro beneficio de la API provideRouter es que se puede hacer tree-shaking! Los empaquetadores pueden eliminar las funciones no utilizadas del enrutador en el momento de la compilación. En nuestras pruebas con la nueva API, descubrimos que eliminar estas funciones no utilizadas del paquete resultó en una reducción del 11 % en el tamaño del código del enrutador en el paquete de la aplicación.

API de composición de directivas

¡La API de composición de directivas lleva la reutilización de código a otro nivel! Esta función se inspiró en la solicitud de función más popular en GitHub que solicita la funcionalidad para agregar directivas a un elemento de host.
La API de composición de directivas permite a los desarrolladores mejorar los elementos del host con directivas y equipa a Angular con una poderosa estrategia de reutilización de código, eso solo es posible gracias a nuestro compilador. La API de composición de directivas solo funciona con directivas independientes.

Veamos un ejemplo rápido:

@Component({
  selector: 'mat-menu',
  hostDirectives: [HasColor, {
    directive: CdkMenu,
    inputs: ['cdkMenuDisabled: disabled'],
    outputs: ['cdkMenuClosed: closed']
  }]
})
class MatMenu {}
Enter fullscreen mode Exit fullscreen mode

En el fragmento de código anterior, mejoramos MatMenu con dos directivas: HasColory CdkMenu. MatMenu reutiliza todas las entradas, salidas y la lógica asociada con HasColorsy solo la lógica y las entradas seleccionadas de CdkMenu.

Esta técnica puede recordarle herencia múltiple o rasgos en algunos lenguajes de programación, con la diferencia de que tenemos un mecanismo para la resolución de conflictos de nombres y es aplicable a las primitivas de la interfaz de usuario.

¡La directiva de imagen ahora es estable!

Anunciamos una vista previa para desarrolladores de la directiva de imagen Angular que desarrollamos en colaboración con Chrome Aurora en v14.2.

Image

¡Estamos emocionados de compartir que ahora es estable! Land's End experimentó con esta característica y observó una mejora del 75% en LCP en una prueba de laboratorio de Lighthouse.

La versión v15 también incluye algunas características nuevas para la directiva de imágenes:

  • **srcset** de Generación automática: la directiva garantiza que se solicite una imagen del tamaño adecuado al generar el srcset determinado por usted. Esto puede reducir los tiempos de descarga de sus imágenes.

  • Modo de relleno [experimental]: este modo hace que la imagen llene su contenedor principal, eliminando el requisito de declarar el ancho y el alto de la imagen. Es una herramienta útil si no conoce los tamaños de sus imágenes o si desea migrar imágenes de fondo CSS para usar la directiva.

Puede usar la NgOptimizedImage directiva independiente directamente en su componente o NgModule:

importar {NgOptimizedImage} desde '@angular/common' ; 

// Incluirlo en el NgModule 
@NgModule({ 
  imports: [NgOptimizedImage], 
}) 
class  AppModule {} 
// ... o un componente independiente 
@Component({ 
  standalone: ​​true 
  imports: [NgOptimizedImage], 
}) 
class  MyStandaloneComponent {}
Enter fullscreen mode Exit fullscreen mode

Para usarlo dentro de un componente, simplemente reemplacé el atributo src de la imagen con ngSrc y asegúrese de especificar el atributo priority para sus imágenes LCP.

Puede encontrar más información en nuestra documentación.

Protectores de ruta funcionales (Router Guards)

Junto con las API de rutas independientes al que se puede aplicar three-shaking, trabajamos para reducir la redundancia de código en los protectores. Veamos un ejemplo donde definimos un protector que verifica si el usuario ha iniciado sesión:

@Injectable({ providedIn: 'root' })
export class MyGuardWithDependency implements CanActivate {
  constructor(private loginService: LoginService) {}

  canActivate() {
    return this.loginService.isLoggedIn();
  }
}

const route = {
  path: 'somePath',
  canActivate: [MyGuardWithDependency]
};
Enter fullscreen mode Exit fullscreen mode

LoginService implementa la mayor parte de la lógica y en el protector solo invocamos isLoggedIn(). Aunque la protección es bastante simple, tenemos mucho código repetitivo.

Con los nuevos protectores de enrutadores funcionales, puede refactorizar este código a:

const route = {
  path: 'admin',
  canActivate: [() => inject(LoginService).isLoggedIn()]
};
Enter fullscreen mode Exit fullscreen mode

Escribimos todos los parámetros para la protección dentro de la declaración de protección. Las protecciones funcionales también se pueden componer - puede crear funciones similares a las de fábrica que aceptan una configuración y devuelven una función de protección o resolución. Puede encontrar un ejemplo para ejecutar guardias de enrutador en serie en GitHub.

El enrutador(router) desenvuelve las importaciones predeterminadas

Para hacer que el enrutador sea más simple y reducir aún más el texto estándar, el enrutador ahora desenvuelve automáticamente las exportaciones predeterminadas cuando se realiza una carga diferida.

Supongamos que tiene lo siguiente LazyComponent:

@Component({
  standalone: true,
  template: '...'
})
export default class LazyComponent { ... }
Enter fullscreen mode Exit fullscreen mode

Antes de este cambio, para realizar la carga diferida de un componente independiente, tenía que:

{
  path: 'lazy',
  loadComponent: () => import('./lazy-file').then(m => m.LazyComponent),
}
Enter fullscreen mode Exit fullscreen mode

Ahora el enrutador buscará una exportación predeterminada y, si la encuentra, la usará automáticamente, lo que simplifica la declaración de la ruta a:

{
  path: 'lazy',
  loadComponent: () => import('./lazy-file'),
}

Enter fullscreen mode Exit fullscreen mode

Mejores rastros de pila(Better stack traces)

Obtenemos mucha información de nuestras encuestas anuales para desarrolladores, por lo que queremos agradecerle por tomarse el tiempo para compartir sus pensamientos. Al profundizar en las dificultades con la experiencia de depuración que enfrentan los desarrolladores, descubrimos que los mensajes de error podrían mejorar.

Comentarios sobre los desafíos de depuración

Problemas de depuración para los desarrolladores de Angular

¡Nos asociamos con Chrome DevTools para arreglar esto! Veamos un seguimiento de pila de muestra que puede obtener trabajando en una aplicación Angular:

ERROR Error: Uncaught (in promise): Error
Error
    at app.component.ts:18:11
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (asyncToGenerator.js:3:1)
    at _next (asyncToGenerator.js:25:1)
    at _ZoneDelegate.invoke (zone.js:372:26)
    at Object.onInvoke (core.mjs:26378:33)
    at _ZoneDelegate.invoke (zone.js:371:52)
    at Zone.run (zone.js:134:43)
    at zone.js:1275:36
    at _ZoneDelegate.invokeTask (zone.js:406:31)
    at resolvePromise (zone.js:1211:31)
    at zone.js:1118:17
    at zone.js:1134:33
Enter fullscreen mode Exit fullscreen mode

Este fragmento viene de dos problemas principales:

  • Solo hay una línea que corresponde al código que ha creado el desarrollador. Todo lo demás proviene de dependencias de terceros (marco Angular, Zone.js, RxJS)

  • No hay información sobre qué interacción del usuario causó el error.

El equipo de Chrome DevTools creó un mecanismo para ignorar los scripts que provienen node_modules al anotar los mapas de origen a través de la CLI de Angular. También colaboramos en una API de etiquetado de pila asíncrona que nos permitió concatenar tareas asíncronas programadas e independientes en un único seguimiento de pila. Jia Li integró Zone.js con la API de etiquetado de pilas asíncronas, lo que nos permitió proporcionar seguimientos de pilas vinculadas.

Estos dos cambios mejoran drásticamente los seguimientos de pila que los desarrolladores ven en Chrome DevTools:

ERROR Error: Uncaught (in promise): Error
Error
    at app.component.ts:18:11
    at fetch (async)  
    at (anonymous) (app.component.ts:4)
    at request (app.component.ts:4)
    at (anonymous) (app.component.ts:17)
    at submit (app.component.ts:15)
    at AppComponent_click_3_listener (app.component.html:4)
Enter fullscreen mode Exit fullscreen mode

Aquí puede seguir la ejecución desde que se presiona el botón en AppComponent hasta el error. Puede leer más sobre las mejoras aquí.

Liberaramos componentes basados ​​en MDC a estable

¡Nos complace anunciar que la refactorización de los componentes de material de Angular basados ​​en Componentes de diseño de materiales para Web (MDC) ya está lista! Este cambio permite que Angular se alinee aún más con la especificación de Material Design, reutilice el código de las primitivas desarrolladas por el equipo de Material Design y nos permita adoptar Material 3 una vez que finalicemos los tokens de estilo.

Para muchos de los componentes, hemos actualizado los estilos y la estructura DOM y otros los hemos reescrito desde cero. Mantuvimos la mayoría de las API de TypeScript y los selectores de componente/directiva para los nuevos componentes idénticos a la implementación anterior.

Migramos miles de proyectos de Google, lo que nos permitió simplificar la ruta de migración externa y documentar una lista completa de los cambios en todos los componentes.

Debido al nuevo DOM y CSS, es probable que descubra que es necesario ajustar algunos estilos en su aplicación, especialmente si su CSS anula estilos en elementos internos en cualquiera de los componentes migrados.

La implementación anterior de cada componente nuevo ahora está obsoleta, pero aún está disponible a partir de una importación "heredada". Por ejemplo, puede importar la mat-button anterior importando el módulo de botón legacy.

import {MatLegacyButtonModule} from '@angular/material/legacy-button';Visite la guía de migración para obtener más información.
Enter fullscreen mode Exit fullscreen mode

Movimos muchos de los componentes para usar tokens de diseño y variables CSS debajo del capó, lo que proporcionará un camino fluido para que las aplicaciones adopten los estilos de componentes de Material 3.

Más mejoras en los componentes

Resolvimos el cuarto problema más votado: soporte de selección de rango en el control deslizante.

Para obtener un uso de entrada de rango:

<mat-slider> 
  <input matSliderStartThumb> 
  <input matSliderEndThumb> 
</mat-slider >
Enter fullscreen mode Exit fullscreen mode

Además, todos los componentes ahora tienen una API para personalizar la densidad, lo que resolvió otro problema popular de Github.

Ahora puede especificar la densidad predeterminada en todos sus componentes al personalizar su tema:

@use '@angular/material' as mat;

$theme: mat.define-light-theme((
  color: (
    primary: mat.define-palette(mat.$red-palette),
    accent: mat.define-palette(mat.$blue-palette),
  ),
  typography: mat.define-typography-config(),
  density: -2,
));

@include mat.all-component-themes($theme);
Enter fullscreen mode Exit fullscreen mode

Las nuevas versiones de los componentes incluyen una amplia gama de mejoras de accesibilidad, que incluyen mejores relaciones de contraste, mayores tamaños de objetivos táctiles y semántica ARIA refinada.

Listbox de CDK

El kit de desarrollo de componentes (CDK) ofrece un conjunto de primitivas de comportamiento para crear componentes de interfaz de usuario. En v15 presentamos otra primitiva que puede personalizar para su caso de uso: el listbox CDK:

Experiencia de usuario del listbox de CDK

El módulo @angular/cdk/listbox proporciona directivas para ayudar a crear interacciones de listbox personalizadas basadas en el patrón de listbox WAI ARIA.

Al usar @angular/cdk/listbox, obtienes todos los comportamientos esperados para una experiencia accesible, incluida la compatibilidad con el diseño bidi, la interacción del teclado y la gestión del enfoque. Todas las directivas aplican sus roles ARIA asociados a su elemento host.

Mejoras en el soporte de esbuild experimental

Página de destino de esbuild

En la v14, anunciamos el soporte experimental para esbuild en ng build para permitir tiempos de compilación más rápidos y simplificar nuestra pipeline.

¡En la v15 ahora tenemos Sass experimental, plantillas SVG, reemplazo de archivos y soporte para ng build --watch , Pruebe esbuild actualizando sus constructores angular.json desde:

"builder": "@angular-devkit/build-angular:browser"
Enter fullscreen mode Exit fullscreen mode

a:

"builder": "@angular-devkit/build-angular:browser-esbuild"
Enter fullscreen mode Exit fullscreen mode

Si encuentra algún problema con sus compilaciones de producción, infórmenos presentando el problema en GitHub.

Importaciones automáticas en el servicio de idiomas

El servicio de idioma ahora puede importar automáticamente los componentes que está usando en una plantilla pero que no ha agregado a un componente independiente o un NgModule.

Importaciones automáticas de servicios de idiomas

Mejoras en el CLI

En CLI de Angular introdujimos soporte para API estables independientes. Ahora puede generar un nuevo componente independiente a través de ng g component --standalone.

También tenemos la misión de simplificar la salida de ng new. Como primer paso, reducimos la configuración eliminando test.ts, polyfills.ts y environments. Ahora puede especificar sus polyfills directamente angular.json en la sección polyfills:

"polyfills" :  [ 
  "zone.js" 
]
Enter fullscreen mode Exit fullscreen mode

Para reducir aún más la sobrecarga de configuración, ahora usamos .browserlist para permitirle definir la versión de destino de ECMAScript.

Aspectos destacados de la contribución de la comunidad

¡Estamos agradecidos de compartir que desde el lanzamiento de v14 recibimos contribuciones de más de 210 personas en el marco, los componentes y el CLI! En este apartado me gustaría destacar dos de ellos.

Proporcionar la capacidad de configurar las opciones predeterminadas para DatePipe

Esta función le permite cambiar globalmente la configuración de formato predeterminada para DatePipe. Aquí hay un ejemplo con la nueva bootstrapApplication API:

bootstrapApplication (AppComponent, { 
  proveedores : [ 
    { 
      proporcionar : DATE_PIPE_DEFAULT_OPTIONS, 
      useValue : { dateFormat : 'shortDate' } 
    } 
  ] 
});
Enter fullscreen mode Exit fullscreen mode

La configuración anterior habilitará shortDate el formato para todos los lugares que utilice DatePipeen su aplicación.

Agregar etiqueta de precarga para imágenes prioritarias durante SSR

Para asegurarse de que las imágenes prioritarias se carguen lo más rápido posible, Jay Bell agregó una funcionalidad a la directiva de imagen para incluir una etiqueta para cuando se usa Angular Universal.

No se necesita ninguna acción de su parte si ya ha habilitado la directiva de imagen. Si ha especificado una imagen como prioridad, la directiva la precargará automáticamente.

Deprecaciones

Los lanzamientos principales nos permiten evolucionar el framework hacia la simplicidad, una mejor experiencia del desarrollador y la alineación con la plataforma web.

Después de analizar miles de proyectos dentro de Google, encontramos algunos patrones poco utilizados que, en la mayoría de los casos, se utilizan incorrectamente. Como resultado, estamos descartando providedIn: 'any' una opción que tiene un uso muy limitado, aparte de un puñado de casos esotéricos internos del framework.

También estamos deprecando providedIn: NgModule. No tiene un uso generalizado, y en la mayoría de los casos se usa de forma incorrecta, en circunstancias en las que debería preferir providedIn: 'root'. Si realmente desea apuntar a un NgModule, utilíce NgModule.providersen su lugar.

Con la evolución del diseño en CSS, el equipo dejará de publicar nuevas versiones de @angular/flex-layout. Continuaremos brindando correcciones de seguridad y compatibilidad del navegador durante el próximo año. Puede obtener más información sobre esto en la primera publicación de blog de nuestra serie "CSS moderno".

¡Emocionado por lo que viene a continuación!

El lanzamiento de Ivy en 2020 permitió muchas mejoras en todos los ámbitos que puede encontrar que ya se están implementando. NgModules opcional es un gran ejemplo. Ayuda a reducir los conceptos con los que los principiantes deben lidiar como parte de su viaje de aprendizaje crítico y también admite funciones avanzadas como la API de composición de directivas a través de directivas independientes.

A continuación, abordaremos las mejoras en nuestra pipeline de renderizado del lado del servidor y la reactividad, al mismo tiempo que brindamos mejoras en la calidad de vida en todos los ámbitos.

¡No puedo esperar para compartir con ustedes lo que viene a continuación!

Top comments (0)