VOLVER

Moviendo grandes partes a Angular 2

5 min de lectura

En un post anterior expliqué cómo convertí Jangouts en una aplicación híbrida Angular 1+2. Este enfoque, en lugar de una migración completa, tiene dos objetivos. Primero, probar la funcionalidad resulta más fácil ya que Jangouts sigue siendo ejecutable. Segundo, si no puedo terminar la migración, otros pueden continuar el trabajo. Espero que este respaldo resulte innecesario.

Con el enfoque híbrido implementado, esta semana migré varios componentes a Angular 2. Empecé con el componente Chat---más complejo que el Footer, pero manejable para estas etapas iniciales.

Migrando subcomponentes

El componente Chat de Jangouts tiene tres subcomponentes además del componente principal:

  • chat-message: Renderiza los mensajes del usuario.
  • log-entry: Renderiza las notificaciones del sistema (como "El usuario X se ha unido").
  • chat-form: Maneja la entrada de mensajes.

Estos subcomponentes son simples: cada uno tiene una clase de componente mínima y una plantilla. El cambio clave: los estilos pasaron del archivo scss principal a archivos independientes para cada subcomponente. Esto aprovecha Angular 2 View Encapsulation, asegurando que los estilos se apliquen solo a su componente.

Durante la migración de chat-message, encontré un problema con ngEmbed, la librería que proporciona una directiva para renderizar mensajes de usuario. Esta directiva habilita emojis y enlaces, imágenes y vídeos incrustados. La librería carece de soporte para Angular 2, así que probé el Angular 2 Upgrade Adapter, pero encontré un error extraño.

La investigación reveló que ngEmbed usa una función como atributo templateUrl (permitido en Angular 1). Sin embargo, el adaptador de actualización de mi versión actual de Angular 2 carece de soporte para templateUrl basado en funciones. La rama master de Angular 2 incluye este soporte, pero ninguna versión publicada lo incorpora aún. Después de discutir con mis mentores, decidimos deshabilitar esta funcionalidad y continuar la migración.

Espero re-habilitarlo en el futuro.

Diferenciar entre componente y directiva

Migrar el componente principal resultó más complejo. Muestra todos los mensajes (de usuario y sistema) en una vista que hace auto-scroll cuando llegan nuevos mensajes. En el antiguo Jangouts, una directiva renderizaba la lista de mensajes y controlaba el auto-scroll. Angular 2 requiere un enfoque diferente: los componentes siempre tienen plantillas y nunca interactúan directamente con el DOM; las directivas nunca tienen plantillas pero pueden interactuar con el DOM.

Esto significó dividir el componente principal del chat en dos partes:

  • Un componente para renderizar la lista de mensajes.
  • Una directiva para manejar el auto-scroll.

Después de la migración, el componente renderiza la lista de mensajes y contiene la directiva que maneja el auto-scroll.

Poniendo todo junto

Durante la migración de subcomponentes, degradé cada uno para compatibilidad con Angular 1 usando el adaptador de Angular 2 y probé manualmente con el antiguo componente principal. Cuando migré el componente principal, su código se convirtió en Angular 2 puro (sin subcomponentes degradados). Solo el componente principal del chat necesitó degradación para compatibilidad con Angular 1.

Aplicando la estructura de aplicación correcta

Los cambios de esta semana fueron más allá del código. También reestructuré la aplicación siguiendo las recomendaciones de la guía de estilo. Antes de la migración, la estructura era:

src
└── app
   ├── adapter.ts
   ├── variables.scss
   ├── index.scss
   ├── vendor.scss
   ├── index.ts
   ├── components
   │   ├── chat
   │   │   ├── chat-form.directive.html
   │   │   ├── chat-form.directive.js
   │   │   ├── chat.directive.html
   │   │   ├── chat.directive.js
   │   │   ├── chat-message.directive.html
   │   │   ├── chat-message.directive.js
   │   │   ├── log-entry.directive.html
   │   │   └── log-entry.directive.html
   │   ├── footer
   │   │   ├── footer.directive.html
   │   │   └── footer.directive.js
   │   └── [...]
   └── [...]

Después de los cambios:

src
└── app
   ├── adapter.ts
   ├── variables.scss
   ├── index.scss
   ├── vendor.scss
   ├── index.ts
   ├── chat
   │   ├── index.ts
   │   ├── chat.component.html
   │   ├── chat.component.scss
   │   ├── chat.component.spec.ts
   │   ├── chat.component.ts
   │   ├── chat-form
   │   │   ├── chat-form.component.html
   │   │   ├── chat-form.component.spec.ts
   │   │   ├── chat-form.component.ts
   │   │   └── index.ts
   │   ├── chat-message
   │   │   ├── chat-message.component.html
   │   │   ├── chat-message.component.scss
   │   │   ├── chat-message.component.spec.ts
   │   │   ├── chat-message.component.ts
   │   │   └── index.ts
   │   ├── log-entry
   │   │   ├── index.ts
   │   │   ├── log-entry.component.html
   │   │   ├── log-entry.component.spec.ts
   │   │   └── log-entry.component.ts
   │   └── message-autoscroll.directive.ts
   ├── footer
   │   ├── footer.component.html
   │   ├── footer.component.scss
   │   ├── footer.component.spec.ts
   │   ├── footer.component.ts
   │   └── index.ts
   ├── components
   │   └── [...] // Esto contiene el código no migrado
   └── [...]

Trabajando actualmente

Ahora estoy migrando el componente Feed, uno de los más complejos en la aplicación debido a sus muchos servicios que manejan streams de vídeo/audio.

He movido todos los servicios y factorías a Angular 2, pero aún no he habilitado la compatibilidad con Angular 1. La razón: quiero una suite de tests completa cubriendo estos servicios antes de continuar la migración e integrar con el resto de la aplicación.