Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Usar Lazy load en componentes Angular
Angular Firebase profile imageAntonio Cardenas
Antonio Cardenas forAngular Firebase

Posted on • Edited on • Originally published atMedium

     

Usar Lazy load en componentes Angular

con ivy en Angular 9

Lazy loading en componentes Angular? 🤔Quizás quieras decir módulos lazy loading con el router de Angular!

¡No, lo has leído correctamente , lazy loading en componentes!

Si, la versiónes pre ivy de Angular solo soportan lazy loading de módulos . Pero Ivy abre un nuevo mundo de posibilidades.

Lazy loading hasta ahora— Rutas Lazy loaded

El Lazy loading es una gran característica. En Angular, lo obtenemos casi gratis al declarar una ruta lazy.

Lazy loading a module in Angular / source: angular.io

El código anterior generaría un fragmento separado para elcustomers.module que se carga tan pronto como llegamos a la ruta decustomer-list.
Es una forma muy bonita de reducir el tamaño de su paquete principal y aumentar la carga inicial de su aplicación.
Aún así, ¿no sería genial si tuviéramos un control aún más granular sobre el lazy loading? Por ejemplo, ¿mediante el lazy loading de componentes individuales?
El lazy loading de componentes individuales no ha sido posible hasta ahora. Pero las cosas han cambiado con Ivy.

🌱 Ivy introduce “localidad”.

Los módulos son un concepto de primera clase y el componente principal de todas las aplicaciones de Angular. Declaran varios componentes, directivas, pipes y servicios.

Las aplicaciones Angular de hoy no pueden existir sin módulos. Una de las razones de esto es que el ViewEngine agrega todos los metadatos necesarios a los módulos.

Ivy, por otro lado, adopta otro enfoque. En Ivy, un componente puede existir sin un módulo. Gracias a un concepto llamado “Localidad”.

"Localidad" significa que todos los metadatos son locales al componente.

Permítanme explicar esto echando un vistazo más de cerca a un paquete es2015 generado con Ivy.

es2015 bundle generated with Ivy 🌱

En la sección "Código de componente", podemos ver que Ivy mantiene nuestro código de componente. Nada especial. Pero luego Ivy también le agrega algunos metadatos.

El primer metadato que agrega es un Factory que sabe cómo instanciar nuestro componente ("Component Factory"). En la parte de "Metadatos de componentes", Ivy agrega más atributos comotype,selector, etc., todo lo que necesita en tiempo de ejecución.

Una de las cosas más interesantes que agrega Ivy es la función detemplate. Lo que merece algunas explicaciones adicionales.

La función de plantilla es la versión compilada de nuestro HTML. Ejecuta las instrucciones de Ivy para crear nuestro DOM. Esto difiere de la forma en que funcionaba ViewEngine.

El ViewEngine tomó nuestro código y lo repitió. Angular estaba ejecutando código si lo estábamos usando.

Con el enfoque Ivy, el componente está en el asiento del conductor y ejecuta Angular. Este cambio permite que un componente viva por sí solo y hace que el núcleo angular se le pueda aplicar tree-shaking

Un ejemplo del mundo real de un componente Lazy Loading

Un ejemplo del mundo real de carga diferida de un componente
Ahora que sabemos que la carga diferida es posible, lo demostraremos en un caso de uso del mundo real. Vamos a implementar una aplicación Quiz.
La aplicación muestra una imagen de la ciudad con diferentes posibles soluciones. Una vez que un usuario elige una solución, el botón en el que se hace clic muestra inmediatamente si la respuesta fue correcta o no volviéndose rojo o verde.
Después de responder una pregunta, aparece la siguiente pregunta. Aquí tienes una vista previa rápida:

El concepto de de un componente lazy loading👨‍🎓

Primero, ilustremos la idea general de la carga diferida de nuestro componenteQuizCard.

Una vez que el usuario inicia el quiz haciendo clic en el botón "Start Quiz", comenzamos a cargar nuestro componente usando lazy load. Una vez que tengamos el componente, lo agregaremos a un contenedor.

Reaccionamos a los eventos de salidaquestionAnwsered de nuestro componente lazy-loaded como lo hacemos con los componentes estándar. Una vez que ocurre el evento de salidaquestionAnwsered, agregamos una nueva tarjeta Quiz.

Entendido, echemos un vistazo al código 🔍

Para explicar el proceso de carga diferida de un componente, comenzaremos con una versión simplificada de nuestroQuizCardComponent que muestra de manera simplista las propiedades de la pregunta.

Luego, ampliaremos nuestro componente agregando componentes de Material angular. Por último, pero no menos importante, reaccionamos a los eventos de salida de nuestro componente de carga diferida.

Entonces, por ahora, carguemos una versión simplificada delQuizCardComponent que tiene la siguiente plantilla:

El primer paso es crear un elemento contenedor. Para esto, usamos un elemento real como un div o podemos usar un ng-container, que no introduce un nivel extra de HTML.

Genial, tenemos el contenedor donde queremos agregar nuestro componente lazy-loaded. A continuación, necesitamos un ComponentFactoryResolver y un Injector que podemos utilizar ambos mediante inyección de dependencia.

Un ComponentFactoryResolver es un registro simple que asigna componentes a clases de ComponentFactory generadas que se pueden usar para crear instancias de componentes.

Ok, en este punto, tenemos todas las cosas que necesitamos para lograr nuestro objetivo. Cambiemos nuestro método startQuiz y carguemos nuestro componente de manera lazy load.

Podemos usar la funciónimport de ECMAScript para usar lazy load en nuestro QuizCardComponent. La declaración de importación nos devuelve una promesa que manejamos usando async/await o con un controlador then. Una vez que la promesa se resuelve, usamos la desestructuración para hacer grep al componente.

No useasync/await cuando compile enes2017. Zone js no puede parchear declaraciones nativasasync/await. Por lo tanto, puede tener problemas con la detección de cambios. Si compila su código enes2017, debe usar un controlador .then con una función de devolución de llamada.

Para ser compatible con versiones anteriores, hoy en día necesitamos unComponentFactory. Esta línea no será necesaria en el futuro ya que podemos trabajar directamente con el componente.

ElComponentFactory nos da uncomponentRef que luego, junto con el Injector, pasaremos al métodocreateComponent de nuestro contenedor.

ElcreateComponent nos devuelve unComponentRef que contiene una instancia de nuestro componente. Usamos esta instancia para pasar las propiedades de@Input a nuestro componente.

En el futuro, todo esto podría hacerse utilizando el método renderComponent de Angular. Este método todavía es privado/experimental. Sin embargo, es muy probable que este método llegue a Angular. Lars Gyrup Brink Nielsen dio un gran taller sobre esto en InDepthConf.

Eso es todo lo que se necesita para cargar un componente usando lazy load.

Una vez que se hizo clic en el botón de inicio, cargamos nuestro componente usando lazy load. Si abrimos la pestaña de red, podemos ver que el fragmento quiz-card-quiz-card-component.js a sido cargado mediante lazy load. En la aplicación en ejecución, se muestra el componente y se muestra la Pregunta.

Agreguemos material 👷

Actualmente, cargamos nuestroQuizCardComponent mediante lazy load. Muy genial. Pero nuestra aplicación aún no es útil.

Cambiemos eso agregando características adicionales y algunos componentes de Angular material.

Incluimos algunos hermosos componentes de Material. Pero, ¿dónde agregamos los módulos de material?

Sí, podríamos agregarlos a nuestro AppModule. Pero, esto significa que esos módulos se cargan ansiosamente (eagerly loaded). Entonces esa no es la mejor solución. Además, nuestra compilación falla con el siguiente mensaje:

ERROR in src/app/quiz-card/quiz-card.component.html:9:1 - error TS-998001: 'mat-card' is not a known element:1. If 'mat-card' is an Angular component, then verify that it is part of this module.2. If 'mat-card' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
Enter fullscreen modeExit fullscreen mode

¿Ahora que? Como puedes imaginar, existe una solución a este problema. ¡Y la respuesta son módulos!
Pero esta vez los usaremos de manera ligeramente distinta. Agregamos un pequeño módulo al mismo archivo que nuestroQuizCardComponent.

Esta especificación de módulo solo pertenece a nuestro componente lazy loaded. Por lo tanto, el único componente que este módulo declarará es el QuizCardComponent. En la sección de imports, solo agregamos los Módulos necesarios para nuestro componente.
Para asegurarnos de que un módulo cargado ansiosamente (eagerly loaded) no pueda importar el módulo, no lo exportamos.
Volvamos a ejecutar nuestra aplicación y veamos cómo se comporta cuando hacemos clic en el botón "Start Quiz".

¡Increíble! NuestroQuizCardComponent se carga de manera lazy loaded y se agrega al ViewContainer. También trae todas las dependencias necesarias.

Usemos una herramienta llamada webpack-bundle-analyzer y analicemos el aspecto del paquete.

webpack-bundle-analyzer es un módulo npm que le permite visualizar el tamaño de los archivos de salida del paquete web con un mapa de árbol interactivo con zoom.

El tamaño de nuestro paquete principal es de alrededor de 260 KB. Si cargáramos de manera ansiosamente (eagerly loaded) el,QuizCardComponent sería de alrededor de 270 KB. Ahorramos alrededor de 10 KB cargando de forma diferida solo este componente. ¡Muy genial!

NuestroQuizCardComponent se incluyó en un bloque separado. Si echamos un vistazo más de cerca al contenido de este fragmento, no solo encontramos nuestro códigoQuizCardComponent, sino que también vemos los módulos Material utilizados dentro delQuizCardComponent.

AunqueQuizCardComponent usóMatButtonModule yMatCardModule, solo MatCardModule termina en el fragmento del componente de la tarjeta de prueba. La razón de esto es porque también usamosMatButtonModule en nuestro AppModule para mostrar el botón de inicio de prueba. Por lo tanto, termina en otro trozo.

En este punto, cargamos de manera lazy-loaded nuestroQuizCardComponent, que muestra una hermosa tarjeta de Material con una imagen y algunas posibles respuestas. Pero, ¿sucede actualmente si hace clic en una de esas posibles respuestas?

Según su respuesta, el botón se vuelve verde o rojo. ¿Pero además de eso? ¡Nada! Entonces ahora se muestra otra pregunta. Arreglemos eso.

Reaccionar ante eventos de componentes con lazy loading

No se muestran más preguntas porque aún no reaccionamos al evento de salida de nuestro componente lazy-loaded. Ya sabemos que nuestroQuizCardComponent emite eventos usando unEventEmitter. Si miramos la definición de clase deEventEmitter, podemos ver queEventEmitter hereda deSubject.

export declara la clase EventEmitter <T extiende cualquiera> extiende Subject <T>
Enter fullscreen modeExit fullscreen mode

Significa queEventEmitter también tiene un método de suscripción, que nos permite reaccionar a los eventos emitidos.

Nos suscribimos al flujo questionAnswered y llamamos al método showNextQuestion, que luego ejecuta nuestra lógica lazyLoadQuizCard.

takeUntil(instance.destroy$) es necesario para limpiar la suscripción una vez que el componente se destruya. Si se llama al gancho del ciclo de vida (lifecycle hook)ngOnDestroy deQuizCardComponent, se llama adestroy$ elSubject es llamado connext ycomplete.

async showNewQuestion() {  this.lazyLoadQuizCard();}
Enter fullscreen modeExit fullscreen mode

Dado que laQuizCard ya se cargó, no se ha realizado ninguna solicitud HTTP adicional. Usamos el contenido del fragmento cargado previamente, creamos un nuevo componente y lo agregamos a nuestro contenedor.

Ganchos de ciclo de vida(Life cycle hooks)

Casi todos los enganches del ciclo de vida se llaman automáticamente si cargamos de manera lazy load nuestroQuizCardComponent. Pero falta un gancho, ¿ves cuál?

Es el primero de todos los ganchos,ngOnChanges. Dado que actualizamos manualmente las propiedades de entrada de nuestra instancia de componente, también somos responsables de llamar al enlace del ciclo de vidangOnChanges.

Para llamar angOnChanges en la instancia, necesitamos construir manualmente elobjectSimpleChanges.

Llamamos manualmente angOnChanges en nuestra instancia de componente y le pasamos un objeto SimpleChange. ElSimpleChange indica que es el primer cambio, que el valor anterior eranull y que el valor actual es nuestra pregunta.

¡Increíble! Cargamos de forma diferida un componente con módulos de terceros, reaccionamos a los eventos de salida y llamamos a los enlaces correctos del gancho ciclo de vida(life cycle hooks).

¿Te Interesa el código fuente?

Todas las fuentes utilizadas a lo largo de esta publicación de blog están disponibles públicamente en el siguiente repositorio.

https://github.com/kreuzerk/city-quiz

Conclusión

El componente mediante Lazy loading ofrece grandes posibilidades para optimizar aún más nuestra aplicación en lo que respecta al rendimiento. Tenemos un control más granular de lo que queremos cargar en forma diferida en comparación con las funciones de carga diferida con el enrutador angular.

Desafortunadamente, todavía necesitamos módulos cuando usamos otros módulos en nuestro componente. Tenga en cuenta que es muy probable que esto cambie en el futuro.

Ivy usa la localidad, lo que permite que los componentes vivan por sí mismos. Este cambio es la base para el futuro de Angular.

🧞‍ 🙏 Si te gustó esta publicación, compártela y aplaude👏🏻 haciendo clic varias veces en el botón de aplaudir en el lado izquierdo.

Los aplausos ayudan a otras personas a descubrir contenido y me motivan a traducir más artículos 😉

Ng-sorting

https://www.npmjs.com/package/ng-sortgrid

Muchísimas gracias aLars Gyrup Brink Nielsen y al autorKevin Kreuzer de esta maravilloso articulo, ahora muchos artículos de Angular estarán en español.

Articulo original si lo deseas ver en ingles 
https://medium.com/angular-in-depth/lazy-load-components-in-angular-596357ab05d8

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

web-dev

More fromAngular Firebase

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp