Primera semana de codificación
La primera semana del periodo de codificación de GSoC 2016 ha terminado. Empecé la actualización de Jangouts de Angular 1.x a Angular 2. Completé todas las tareas dentro del plazo y espero mantener este ritmo la próxima semana.
Estoy siguiendo la guía de actualización de la documentación oficial de Angular, que tiene dos bloques principales:
- Preparación
- Actualización con el Adaptador de Actualización
Acabo de terminar el bloque de preparación. Afortunadamente, el código de
Jangouts es claro y ya sigue dos requisitos clave de preparación: la guía de
estilo de Angular y directivas de componentes. Esto me dejó solo dos tareas:
cambiar de etiquetas <script> a un cargador de módulos, y migrar de JavaScript
a TypeScript. Invertí el orden, migrando a TypeScript primero y luego cambiando
al cargador de módulos. Esta secuencia me pareció más natural para este
proyecto.
Migrando a TypeScript
Jangouts tiene un sistema de construcción gulp funcionando, así que no necesité
preocuparme por la carga de scripts. Me enfoqué primero en migrar archivos a
TypeScript, luego aproveché la sintaxis import de TypeScript/ES6.
Migrar código de JavaScript a TypeScript es sencillo: cambia la extensión de
.js a .ts. El sistema gulp existente no funciona con estos cambios, así que
ejecuta tsc --watch src/**/*.ts junto con gulp. Este comando muestra muchos
errores, pero si el código JavaScript es correcto, estos errores solo se
relacionan con la comprobación de tipos de TypeScript.
Durante esta migración, también hice el código más modular. Jangouts tenía todos
los componentes registrados en un único módulo Angular janusHangouts. De
proyectos anteriores, aprendí que esto causa problemas con pruebas unitarias.
Ahora defino un módulo separado para cada componente
(janusHangouts.componentName) y lo hago dependencia del módulo principal. Esto
tiene dos ventajas: testing más fácil, y potencialmente cargar componentes bajo
demanda con un cargador de módulos.
Como mencioné antes, compilar código JavaScript con tsc muestra muchos
errores. Un error común es:
error TS7006: Parameter '$state' implicitly has an 'any' type.
El compilador TypeScript requiere un tipo para todas las variables. Para
permitir tipos any implícitos en variables sin tipo, deshabilita
noImplicitAny en tsconfig.json.
Otro error que podemos encontrar al trabajar con elementos HTML es:
error TS2339: Property 'muted' does not exist on type 'HTMLElement'.
Este error se produce por un código como este:
var video = $("video", element)[0];video.muted = true;
TypeScript es seguro en tipos: $('video', element)[0] devuelve HTMLElement,
que no tiene la propiedad muted. El subtipo HTMLVideoElement sí contiene
muted. Castea el resultado a HTMLVideoElement:
var video = <HTMLVideoElement>$('video', element)[0];video.muted = true;
Finalmente, otro error común es:
error TS2339: Property 'id' does not exist on type '{}'.
La validación de tipos de TypeScript causa este error en código como:
var room = {};// Algún código aquí...function isRoom(room) {return room.id == roomId;}
Define una interfaz para el objeto room para solucionar esto y reducir errores:
interface Room {id?: number; // ? hace el atributo opcional}// Algún código aquí ...var room: Room = {};// Algún código aquí...function isRoom(room: Room) {return room.id == roomId;}
Usando un Cargador de Módulos
¿Por qué usar un cargador de módulos? El sitio de Angular explica:
Usar un cargador de módulos como SystemJS, Webpack, o Browserify nos permite usar los sistemas de módulos integrados de los lenguajes TypeScript o ES2015 en nuestras aplicaciones. Podemos usar las características de import y export que explícitamente especifican qué código puede y será compartido entre diferentes partes de la aplicación. [...]
Cuando luego llevamos nuestras aplicaciones a producción, los cargadores de módulos también hacen más fácil empaquetarlas todas en paquetes de producción con baterías incluidas.
Descarté Browserify por malas experiencias pasadas y solo probé SystemJS y Webpack.
SystemJS
SystemJS parece limpio y simple. Define un punto de entrada (típicamente el
archivo principal de la aplicación) y la sintaxis import hace el resto. Con
declaraciones import correctas, todo funciona.
Sin embargo, esta solución requiere conservar gulp ya que SystemJS solo maneja importaciones. Esto significa añadir el compilador TypeScript a gulp y deshabilitar la auto inyección de scripts en HTML.
Antes de reescribir la configuración de gulp, quería probar Webpack primero.
Webpack
La configuración de Webpack es más compleja que SystemJS, pero reemplaza gulp
completamente. Como SystemJS, definimos un punto de entrada y especificamos
dónde está index.html para la inclusión de archivos JavaScript.
Tuve problemas iniciales, pero tras estudiar ejemplos, conseguí una versión
funcional. Explorando Webpack más a fondo, encontré lo que me hizo elegirlo:
podemos hacer import o require de archivos no JavaScript. Podemos requerir
la plantilla de una directiva Angular, y el proceso de construcción la incluye
como variable string dentro del componente. Los estilos funcionan igual. Esto
mejora el rendimiento empaquetando todos los archivos que un componente necesita
en su archivo JavaScript, sin complicar el desarrollo.
Una cosa más
Este verano parece emocionante con todo lo que aprenderé a través de GSoC. Sigue mi progreso en este blog o a través de mis contribuciones en GitHub. También publiqué un tablero de Trello con la planificación y tareas del proyecto (aún actualizándose).