Moviendo grandes partes a Angular 2
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.