Aurelia… lo nuevo después de Durandal

Seguro que muchos de vosotros conocéis Durandal, la librería para crear aplicaciones SPA ideada por Rob Eisenberg autor también de otras librerías como Caliburn y con cierta obsesión por las espadas…

Hacé algún tiempo Rob anunció que se había unido al equipo de Angular para colaborar con el desarrollo de la versión 2.0 de dicha librería y que Angular y Durandal convergerían en una única librería. Eso generó muchas reacciones, algunas positivas, otras no tanto. A pesar de que Durandal tenía sus usuarios la verdad es que no había conseguido, ni mucho menos, la popularidad de Angular que con esas noticias parecía convertirse en el standard de facto para crear aplicaciones SPA (si es que ya no lo era).

Posteriormente Rob anunció que dejaba el equipo de Angular debido a diferencias en como tenía que evolucionar la librería. Así que anunció que Durandal seguiría su camino y que evolucionaría de forma independiente a Angular y que en fin… todo seguía más o menos como antes. También prometía novedades sobre Durandal NextGen, la versión que tenía en mente y que nunca hubiese existido si Rob se hubiese quedado en el equipo de Angular.

Y finalmente Rob anuncia la aparición de Aurelia, su nuevo framework para aplicaciones SPA. Ya… para seguir la tradición lo podría haber llamado Hrunting o Glamdring o ya puestos Tizona pero no… ha optado por Aurelia. Nuevo nombre para dejar claro que no se trata de una evolución de Durandal si no de una librería totalmente nueva, diseñada desde cero y pensada para ser moderna: está escrita integramente en ES6 aunque transpilada (vaya palabreja) y pollyfilizada (otra palabreja… lo siento por los de la RAE) para trabajar con los navegadores evergreen de hoy en día (un navegador evergreen es aquel del cual no importa su versión por estar siempre actualizado. Si te pregunto tu versión de Chrome o Firefox dudo que la sepas exactamente, esos son los navegadores evergreen).

A diferencia de Angular, Aurelia es más un conjunto de librerías que de forma conjunta forman un framework. Así se pueden usar las librerías sueltas para pequeñas tareas o bien utilizarlas todas en conjunto para crear aplicaciones SPAs. Eso tiene la ventaja de que uno solo paga por lo que usa y que la curva de aprendizaje es, a priori, más suave en tanto se pueden incorporar los conceptos de forma más independiente (en Angular todo está muy atado y es difícil explicar los conceptos de forma separada).

Empezando con Aurelia

Las instrucciones para empezar están todas en http://aurelia.io/get-started.html. Básicamente antes se tiene que instalar gulp y jspm. El primero se usará como sistema de build y el segundo se usa como gestor de paquetes. Esas dos herramientas no forman parte de Aurelia como tal y podrías usar grunt o bower si lo prefieres (asumiendo que los paquetes de Aurelia estén subidos en bower que no lo sé), pero todos los ejemplos de la página web de Aurelia están en glup y jspm.

Veamos lo mínimo necesario para usar Aurelia. Para ello partimos de un directorio vacío y ejecutamos jspm install aurelia-bootstrapper lo que nos instalará un montón de dependencias.

Ahora vamos a necesitar crear tres ficheros:

  • El bootstrapper o lanzador de nuestra aplicación
  • La vista
  • El viewmodel

Vemos pues que Aurelia usa el patrón MVVM y en efecto tiene enlace bidireccional entre la vista y el viewmodel asociado. Veamos cada uno de esos componentes.

El lanzador (index.html) es el encargado de cargar aurelia y lanzar la vista inicial:

  1. <!doctype html>
  2. <html>
  3. <head>
  4. </head>
  5. <body aurelia-app>
  6.     <script src="jspm_packages/system.js"></script>
  7.     <script src="config.js"></script>
  8.     <script>
  9.     System.baseUrl = 'myapp';
  10.     System.import('aurelia-bootstrapper').catch(console.error.bind(console));
  11.     </script>
  12. </body>
  13. </html>

La línea clave aquí es la que establece System.baseUrl a “myapp”. Eso le indica a Aurelia que cargue la vista myapp/app.html y el viewmodel asociado myapp/app.js.

Empecemos por ver el viewmodel que es una clase pura de JavaScript:

  1. export class Welcome{
  2.     constructor(){
  3.         this.name = 'Eduard Toms';
  4.         this.twitter = '@eiximenis';
  5.     }
  6.  
  7.     get twitterUri() {
  8.         return `http://twitter.com/${this.twitter}`;
  9.     }
  10.  
  11.     welcome(){
  12.         alert(`Welcome ${this.name}!`);
  13.     }
  14. }

Aunque quizá no te lo parezca eso es JavaScript puro, concretamente EcmaScript 6, que tiene entre otras características la posibilidad de definir módulos y clases. En este caso el el fichero myapp/app.js es un módulo que se limita a exportar una sola clase llamada Welcome.

Observa también que las propiedades twitterUri() y welcome() usan cadenas pero con el carácter ` (tilde abierta) y no con la comilla simple (ya, el coloreado de código falla totalmente :p). Esa es otra característica de ES6 llamada string interoplation. Sí… ES6 viene cargado con un montón de novedades.

Finalmente nos queda la vista. Las vistas son pedazos de html encapsulados dentro de una etiqueta template:

  1. <template>
  2.     <section>
  3.         <h2>${heading}</h2>
  4.         <form role="form" submit.delegate="welcome()">
  5.             <div class="form-group">
  6.                 <label for="fn">First Name</label>
  7.                 <input type="text" value.bind="name" class="form-control" id="fn" />
  8.             </div>
  9.             <div class="form-group">
  10.                 <label for="ln">Twitter</label>
  11.                 <input type="text" value.bind="twitter" class="form-control" id="ln" />
  12.             </div>
  13.             <div class="form-group">
  14.                 <label>Hello ${name}. Check your twitter account (<a href.bind="twitterUri">${twitter}</a>)?</label>
  15.                 <p class="help-block">${fullName}</p>
  16.             </div>
  17.             <button type="submit" class="btn btn-default">Submit</button>
  18.         </form>
  19.     </section>
  20. </template>

Puedes observar como los enlaces en texto se definen con la sintaxis ${propiedad} (estos enlaces son obviamente unidireccionales). Por otro lado cuando enlazas una propiedad (tal como value o href) se usa la sintaxis propiedad.bind=”propiedad” (p. ej. value.bind o href.bind).

Si ejecutas index.html eso en un navegador que soporte ES6 (p. ej. Chrome) deberás ver algo parecido a:

image

(El alert aparece al pulsar el botón de submit).

Por supuesto si el navegador que tienes no soporta ES6 siempre puedes usar 6to5 para transpilar (es decir convertir xD) el código ES6 usado al ES5 soportado hoy en día para la mayoría de navegadores. Aquí es donde entra gulp en el proceso.  Otra opción es usar directamente ES5 si prefieres. Pero bueno… veremos esto en otro post 🙂

Y bueno… tampoco me ha dado tiempo para ver mucho más de Aurelia. Por lo poco que he visto la idea en general es parecida a Angular o Ember en tanto que usa el patrón MVVM (el viewmodel de Aurelia se corresponde aproximadamente al controlador de Angular) y que soporta enlaces bidireccionales.

Os animo por supuesto a que le echéis un vistazo, al menos para conocerla brevemente… veremos si gana popularidad y se convierte en una alternativa a Angular o se queda en el intento. 🙂

Saludos!

Evento–Bilbostack 2015

Buenas! El sábado (17 de Enero) tuve el placer de asistir al Bilbostack, una conferencia para desarrolladores que se celebra anualmente en Bilbao. En primer lugar felicitar a los organizadores porque la conferencia estaba muy bien montada: el sitio (la universidad de Deusto) era genial al igual que las dos salas usadas para los dos tracks paralelos que había. La primera, el auditorio, simplemente espectacular. La segunda, la sala Gárate, se quedó pequeña en alguna charla (la de IoT con gadgeeter que impartió Quique) pero bueno…

Yo tuve el placer de dar una charla hablando sobre Reactjs, ya sabéis “la librería esa de Facebook” que está ganando mucha tracción ultimamente y que propone un modelo diferente para gestionar nuestra UI. Tengo varios posts a medias sobre Reactjs que espero poder irlos terminando y sacando en breve 😉

Sobre las charlas en general todas muy buenas… Una mención especial para Hugo Biarge que eligió un tema que puede ser muy pero que muy farragoso (las directivas de Angular) pero que contó magistralmente… vamos que creo que incluso alguno se enteró hasta de lo que era la transclusión 😛

Y otra mención especial para Javi Santana: su charla sobre la arquitectura de CartoDB estuvo muy pero que muy bien. No entró en mucho detalle, tuvo un poco de “he venido a vender el producto”, pero lo mejor de la charla fueron “los troleos” que iba soltando, todos ellos muy interesantes y acertados (troleos contra los que quieren usar solo lo último, migrar por si, o usar el nuevo requeteframework sin valorar las implicaciones). Lo dicho, una gran charla para terminar el Bilbostack.

Luego del evento hubo comida-networking-y-todo-eso por la Plaza Nueva tomando los pintxos “en el bar de Jon”… brutales 🙂

Os dejo con el enlace a slideshare de mi presentación.

Ah sí… Y se me olvidaba, jejejeje… felicitar de nuevo a los organizadores por haber hecho que el Beerbao fest coincidiese con el Bilbostack 😛. ¿Qué mejor manera de terminar un evento se os ocurre que tomarse unas buenas cervezas artesanas, eh? 😉

Saludos!!!!

PD: Para ver más info y fotos del Bilbostack os recomiendo seguir a su cuenta de twitter y buscar por el hastag #Bilbostack.

update-database y LocalDb en una aplicación de escritorio

Estos días he estado desarrollando un aplicación de escritorio (wpf aunque eso es lo de menos) que va a hacer uso de LocalDb para guardar datos. Ciertamente no es un escenario muy habitual, ya que al instalar la aplicación en un ordenador cliente se requiere instalar LocalDb pero en este caso eso era asumible. Otras opciones para escritorio podrían pasar por usar algúna BBDD de proceso (como VistaDb o similares).

“Teoricamente” eso no debería diferir del workflow usado en aplicaciones web. Supongamos que tenemos nuestro proyecto con el contexto de EF creado y hemos habilitado migrations (enable-migrations) para controlar las modificaciones del esquema.

Supongamos una cadena de conexión que use AttachDbFilename:

  1. <add name="DbClient" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\App_Data\clientdb_v1.mdf;Initial Catalog=clientdb-v1;Integrated Security=True" providerName="System.Data.SqlClient" />

Se puede observar que se usa |DataDirectory| al igual que en una aplicación web. Esta es una variable de “entorno” que entiende el .NET Framework (a partir de la 4.0.2) y cuyos valores están definidos de la siguiente manera, según se cuenta en este post.

By default, the |DataDirectory| variable will be expanded as follow:

– For applications placed in a directory on the user machine, this will be the app’s (.exe) folder.
– For apps running under ClickOnce, this will be a special data folder created by ClickOnce
– For Web apps, this will be the App_Data folder

Under the hood, the value for |DataDirectory| simply comes from a property on the app domain. It is possible to change that value and override the default behavior by doing this:

      AppDomain.CurrentDomain.SetData("DataDirectory", newpath)

Por lo tanto tenemos que para aplicaciones de escritorio |DataDirectory| se mapea al directorio donde está la BBDD según este post. He de decir que en mi experiencia eso NO es cierto. Se mapea a la subcarpeta App_Data de la carpeta donde está el ejecutable (así, si tenemos el ejecutable en c:xxxbinDebug se mapeará a c:xxxbinDebugApp_Data). Quizá es un cambio posterior a la publicación de este post.

En ejecución se espera que la BBDD (el fichero .mdf) esté en este directorio. Perfecto, pero ahora tenemos el problema de las herramientas de VS. Antes de nada, agregamos un archivo .mdf a nuestra solución (en el startup project):

image

Con esto ya podemos ejecutar update-database y transferir todas las migraciones a este fichero .mdf.

Pero ahora tenemos un problema, y es que los ficheros .mdf son tratados como un fichero “content” tradicional, es decir que lo máximo que VS puede hacer es copiarlos al output folder:

image

Si marcamos:

  1. Copy always: Cada vez que compilemos el proyecto se copiará el .mdf hacia el directorio de ejecución. Resultado: perderemos todos los datos, dado que el .mdf de la solución está vacío (solo tiene el esquema generado por update-database).
  2. Copy if newer: Solo se copiará en caso que el .mdf de la solución sea más nuevo, lo que solo ocurrirá en el caso de cambios de esquema. Entonces en cada cambio de esquema perdemos los datos.
  3. Do not copy: El fichero .mdf no se copia en el directorio de salida, lo que implica que la aplicación… no lo encontrará.

Ninguna de las 3 opciones es deseable. Esto en aplicaciones web no ocurre, debido a la forma en como DataDirectory es gestionado por ASP.NET, pero ahora estamos en escritorio 🙁

Una posible solución es olvidarnos de la copia (Do not copy) y hacer que DataDirectory apunte al fichero .mdf de la solución. Para ello se puede usar AppDomain.CurrentDomain.SetData para conseguir el efecto deseado:

  1. var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\..\..\MyClient\App_Data";
  2. AppDomain.CurrentDomain.SetData("DataDirectory", path);

Básicamente obtenemos el directorio de ejecución del assembly y nos movemos hacia el directorio donde hay realmente el fichero en la solución.

Eso hace que ahora tanto VS al usar update-database como nuestra aplicación usen el mismo fichero .mdf. Por supuesto en cuanto despleguemos de verdad la app deberemos utilizar otra técnica. Porque así dependemos de un fichero (el .mdf) que NO está desplegado en el directorio de salida.

Una solución para ello es volver a poner el “Copy aways” (por lo que el .mdf se copiará cada vez, lo que ahora  no es problema porque tiene datos y esquema) y ejecutar o no la llamada a AppDomain.CurrentDomain.SetData según sea de menester (si se ejecuta la llamada se usa el .mdf de la solución, en caso contrario se usa el .mdf localizado en el directorio de salida).

Un saludo!