viernes, 26 de abril de 2013

Ejemplo lista de tareas con Backbone, RESTEasy y Tapestry

Backbone.js
Normalmente escribo artículos con ejemplos que tratan sobre una única tecnología, al tratar cada tecnología por separado entender que puede ofrecer es más sencillo pero en una aplicación real normalmente se usan varias tecnologías combinadas y al mismo tiempo. Esta entrada aunque sigue siendo un ejemplo es mucho más parecido a lo que podría ser una aplicación real que lo que he explicado durante las últimas entradas. En esta serie sobre javascript he explicado un montón de cosas por separado entre ellas RequireJSMustacheBackbone, servicios rest con Tapestry y RESTEasy. En esta entrada haré un ejemplo haciendo uso de todas las anteriores y alguna cosa más adicional como twitter bootstrap.

El ejemplo consiste en una lista de tareas, pudiéndose introducir nuevas tareas y marcarlas como realizadas. También se podrá eliminar de la lista las tareas completadas y ver un resumen con el número de tareas completadas y de tareas totales.

En la parte cliente de la aplicación se hace uso de RequireJS para manejar la carga de los archivos javascript necesarios, de backbone para gestionar la lista de tareas y realizar la comunicación con el servicio REST del servidor y de Mustache como motor de plantillas para generar la vista (el html). En la parte del servidor usa Tapestry como framework web y RESTEasy como librería para implementar un servicio REST que proporcionará la persistencia en memoria de la lista de tareas.

Backbone permite organizar el código aplicando el patrón de diseño MVC (modelo-vista-controlador) ampliamente extendido en los frameworks web. Este patrón de diseño tiene la ventaja que separa la aplicación en tres partes diferenciadas:
  • El modelo: que contiene los datos del dominio que maneja la aplicación que cuando es modificado lanza eventos para que el controlador y la vista actúen en consecuencia.
  • El controlador: que reacciona ante los eventos que se produzcan en el modelo o por el usuario y modifica adecuadamente el modelo o la vista según el evento.
  • La vista: que a partir del modelo produce la interfaz que se ofrece al usuario para que pueda manipularlos, los eventos producidos en la vista son manejados por el controlador.
Como se ve las tres partes se relacionan entre si pero están separadas de forma que cada una se encargue de una tarea. El código queda bien organizado y se evita el código espagueti que podríamos obtener de otra forma.

En una aplicación con la combinación de Backbone, Mustache y un servicio REST el servidor devuelve el html de la página inicial, las plantillas y los datos del servidor y se delega en el navegador del usuario la tarea de renderizar el html final. Esto tiene la ventaja de que entre el navegador y el servidor viajan menos datos (los datos y las plantillas tendrán menos tamaño que los datos formateados a html) y la parte del servidor se simplifica (no es necesaria la lógica para formatear a html los datos que dependiendo del framework hacen los jsp, tml de tapestry o gsp de grails). Aunque el código de la parte cliente crecerá, el código de la parte del servidor se hará más simple. Una vez cargada la página inicial entre el servidor y el cliente solo viajan los datos en formato json.

Veamos el ejemplo a continuación empezando por el modelo. El modelo con Backbone se define con Backbone.Model.extend, donde podremos indicar las propiedades de los objetos, también podemos definir funciones de utilidad. En este caso el modelo estará formado por los objetos Tarea que tendrán las siguientes propiedades:
  • Un id que identificará la tarea.
  • La descripción de la misma.
  • Y un indicador de si está completada.
Pero en la lista de tareas no solo tendremos un objeto Tarea, tendremos una colección de ellas. Esta colección también forma parte del modelo y se define con Backbone.Collection.extend, los elementos de esta colección serán objetos del modelo Tarea y lo indicamos en la propiedad model, también podemos definir funciones de utilidad como una función para obtener un array con las tareas completadas y otra para eliminar las tareas completadas que nos interesarán para ofrecer la funcionalidad de la lista de tareas. Las propiedades urlRoot y url son importantes para que backbone sepa localizar el servicio REST que proporcionará la persistencia.

La interfaz del servicio web REST es:

En Backbone la vista y el controlador de define en una misma entidad con Backbone.View extend. Aunque se definen ambas cosas a la vez la vista principalmente está formada por el método render, el resto será parte del controlador. Otra sección importante de la vista es la propiedad events donde indicaremos que eventos manejará el controlador y sobre que elementos de la vista, básicamente se define como clave el evento (click, change, ...) y un selector similar a los usados en jquery y como valor el nombre de la función que manejará el evento. En la vista también podremos definir métodos de utilidad. Tendremos dos vistas: una para para una tarea y otra para la aplicación de la lista de tareas.

En el método render se hace uso de Mustache para generar la vista a partir de una plantilla que contiene el código html, la plantilla combinado con los datos del modelo genera un resultado que será incluido en el html de la página. En las funciones initialize se inicializa la vista principalmente para definir que eventos que produzca el modelo serán tratados por el controlador, estos son las funciones on sobre el modelo, por ejemplo, nos interesará saber que se añade, modifica o elimina una tarea de la colección de tareas para actualizar la vista adecuadamente.

En el caso de TareasApp en el método initialize además se inserta en el elemento «el» que se le pasa en el constructor la vista inicial de la aplicación. De esta forma podríamos crear varias instancias de TareasApp.

Las plantillas de Mustache las he definido entre elementos <![CDATA[ ... ]]> ya que las plantillas de Tapestry han de ser xhtml válido, algunas expansiones de Mustache como {{attrs.checked}} de la plantilla tarea-template Tapestry no las entiende como válidas ya que realmente la plantilla Mustache en este caso no es html válido.

Una vez desarrollada la parte del servicio REST en el servidor con RESTEasy integrarlo con Backbone es muy sencillo, únicamente deberemos llamar en los puntos adecuados a las funciones save y destroy de los modelos. Al método save se le llama cuando se añade una nueva tarea en TareasApp.addTarea y cuando se modifica en TareaView.onChangeCompletada. Cuando se hace clic en el botón para limpiar las tareas completadas se llama a la función destroy de cada uno de los modelos. Estos métodos lanzarán las peticiones AJAX al servicio REST de forma automática variando su método y con su correspondiente url según hemos definido con las anotaciones del servicio REST: POST (crear), PUT (actualizar) y DELETE (eliminar).

Petición al crear una nueva tarea
Petición al marcar como completada una tarea
Petición al limpiar tareas completadas
La carga de inicial de la lista de tareas puede hacerse de dos formas: devolviendo los datos de las tareas cuando se pide la página o una vez cargada la página mediante una petición AJAX adicional. En Backbone recomiendan la primera ya que así se evitan peticiones al servidor innecesarias. Además aunque hagamos que las peticiones AJAX sean rápidas probablemente sean lo suficientemente lentas para que el usuario vea como se va rellenando el contenido de la página y dependiendo del html verá como los elementos van cambiando de posición lo cual puede ser molesto. Aunque hay que decir que incluir los datos en la propia página impediría cachear la página. Al final de la página Index.tml, está la sección para cargar la lista inicial de tareas que se pasará a TareasApp después de su constructor en el método resetTareas.

Esta es una captura del ejemplo:

Después de haber usado Backbone en este ejemplo simplemente tengo que decir que es una gran herramienta y que facilita y ayuda a organizar el código javascript en gran medida. Permite separar los datos de la aplicación que forman el modelo del controlador y la vista que reaccionan mediante los eventos producidos en el modelo. También permite desarrollar aplicaciones con un gran peso de javascript en la parte cliente sin que el código se convierta posteriormente en un infierno de mantenimiento aún con la ayuda de jQuery. Es una ayuda tan grande para hacer algunas cosas de la interfaz del cliente como lo es jQuery para manipular los elementos html.

Algunas partes no las he explicado como las plantillas de Mustache, el uso de RequireJS o la parte del servidor del servicio RESTEasy ya que ya lo que he hecho en entradas anteriores que puedes visitarlas mediante sus enlaces.

Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace.

En la siguiente entrada puedes ver el mismo ejemplo pero implementado con Marionette que simplifica algunas cosas respecto a Backbone. Además en el ejemplo de Marionette puedes ver como conseguir internacionalización y como externalizar las plantillas de Mustache del html.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Optimizar módulos de RequireJS y archivos Javascript
Patrón de diseño MVC del lado cliente con Backbone.js

viernes, 19 de abril de 2013

Introducción y ejemplo de Backbone.js

Backbone.js
Las aplicaciones y páginas web están haciendo uso de código javascript cada vez en mayor cantidad para proporcionar aplicaciones con funcionalidades más complejas. En estos momentos las librerías para utilizarse en javascript son muchas y una aplicación puede hacer uso de varias de ellas.

A pesar de las facilidades que proporcionan librerías como jQuery para manipular los elementos de una página web de forma dinámica, mucho código mal estructurado puede llegar a convertirse en un perfecto código espagueti, aunque jQuery facilita y simplifica muchas tareas en el manejo de los elementos de una página no es suficiente, a pesar de jQuery se puede llegar a tener un código con un mar de selectores, mantener sincronizados con la interfaz con el estado de la aplicación y la base de datos puede convertirse en una tarea complicada dar como resultado código con el que apetece poco trabajar.

Backbone.js trata de de resolver algunos de estos problemas proporcionando un marco sobre que el que organizar el código. Backbone.js en esencia en una librería modelo-vista-controlador (MVC) para javascript. Basándose en este patrón de diseño cada parte es independiente del resto. El modelo conserva el estado de la aplicación y produce eventos al ser modificado de forma que la vista se pueda actualizar de una forma independiente para ambos, la vista proporciona la interfaz del controlador a través del que se modifica el modelo de forma adecuada, todos los elementos están relacionados pero cada uno se encarga de una parte.

Patrón de diseño Modelo Vista Controlador (MVC)

Backbone además proporciona una forma para trabajar con servicios REST tanto para recuperar los datos de los modelos como para actualizarlos, guardarlos y eliminarlos en el servidor. A continuación pondré un pequeño ejemplo usando backbone.js que calcula el área de un rectángulo dado su alto y ancho y que lo muestra en pantalla. Como backbone.js sigue el patrón de diseño MVC por un lado tendremos el modelo, en nuestro caso el rectángulo con las propiedades alto y ancho que nos servirán para calcular el área, por el otro la vista que se actualizará según los datos del modelo introducidos en dos campos de texto, finalmente el controlador que captura los eventos como los cambios en los campos de texto, modifica el modelo y el modelo notifica a la vista para que se actualice.

Vemos un ejemplo simple y que muestra parte del potencial de backbone.js. El modelo se define con el siguiente código, además de las propiedades se puede definir funciones que nos puede ser de utilidad, como calcular el área o obtener un objeto para ser utilizado con Mustache:


La otra parte es la vista y el controlador, ambas cosas se definen con Backbone.View.extend:

La inicialización del ejemplo:


Las partes de esta vista-controlador son:
  • el: el elemento html sobre el que actuará la vista.
  • events: los eventos que manejará el controlador, es un mapa donde la clave es un selector muy parecido a jquery y el nombre de la función a llamar cuando se produzca.
  • initialize: con la función de underscore _.bindAll haremos que la referencia a this sea la vista en las funciones indicadas (render, onChangeAlto, onChangeAncho). A continuación se crea el modelo y cuando se produzca algún cambio en él (evento change) se actualice la vista. Finalmente, cuando se inicia la aplicación se dibuja por primera vez la vista.
  • onChangeAlto y onChangeAncho: obtienen el alto o ancho de los campos de texto y modifican el modelo.
  • render: se encarga de actualizar la vista cuando haya algún cambio en el modelo tal y como hemos echo en la función initialize con la función on sobre el modelo. Actualiza los inputs de alto y ancho con los valores del modelo y mediante una plantilla de Mustache forma el mensaje que se visualiza en el  elemento con id resultado.
Finalmente, queda el pequeño código html de la aplicación que contiene los campos de texto para introducir el alto y ancho y el elemento div donde se mostrará el área calculado del rectángulo:



Backbone.js no es la única librería que implementa el patrón MVC en javascript otras alternativas son knockout y AngularJS aunque esta últimas tienen la notable diferencia de que se basan en añadir atributos especiales a las etiquetas html para definir el modelo y asociar los eventos. Backbone.js no necesita añadir esos atributos especiales a la etiquetas html o «instrumentalizarlo», esto se hace a través de javascript lo que da una mayor separación entre el código html y el código javascript. Por ahí se dice que usando backbone.js para realizar lo mismo se necesitan más lineas de javascript pero hay que tener en cuenta que a cambio el html necesario es mucho más simple que en knockout o AngularJS lo que facilita que el trabajo con motores de plantillas como Mustache o Handlebars también sea más simple.

Este pequeño manual de backbone explica muy bien que es. Y el siguiente vídeo es muy interesante.


Como en el resto de entradas sobre esta serie de javascript el código fuente del ejemplo completo lo puedes encontrar en mi repositorio de GitHub. Este ejemplo se basa en RequireJS y Mustache visto en anteriores entradas que puedes consultar en el apartado de referencia al final de la entrada.

En la siguiente entrada mostraré un ejemplo más completo y usando muchas cosas al mismo tiempo de las que he estado hablando individualmente en las últimas entradas (ver referencia), será un ejemplo de una aplicación de lista de tareas por hacer que permite crearlas y completarlas, usará RequireJS, Mustache y Backbone (usándolo de forma más avanzada y completa de lo visto en esta entrada) en la parte cliente y Tapestry y RESTEasy en la parte servidor.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript

viernes, 12 de abril de 2013

Optimizar módulos de RequireJS y archivos Javascript

Una vez que tenemos desarrollada una aplicación que hace uso de RequireJS como herramienta para gestionar las dependencias y archivos de javascript podemos realizar una optimización para conseguir que haya menos archivos y tengan menor tamaño. Esta optimización hará que la aplicación web realice menos peticiones al servidor y necesite transferir menos bytes dando como resultado una aplicación más rápida.

Para conseguir esta optimización necesitamos tener instalado la herramienta node.js y descargar el javascript que realizará la optimización, r.js. En Arch Linux instalar node.js consiste en instalar su paquete con:

Teniendo instalado node.js y habiendo descargado r.js el proceso consiste en ejecutar un comando desde la terminal. Este es:

El contenido del archivo build.js contendrá alguna información como el archivo de salida y la localización del módulo principal de la aplicación, básicamente la configuración es:

Este sería el resultado de optimizar el ejemplo de introducción sobre RequireJS. En el resultado se han eliminado los espacios y tabuladores, los diferentes archivos se han fusionado en uno solo (en este caso únicamente figuras.js y main.js) y los nombres de las variables se han acortado, esto reduce el tamaño del Javascript final. Esta optimización sirve también en cierta forma como ofuscación del código si queremos dificultar a alguien (como a la competencia de un producto) se aproveche del código que hemos desarrollado:


Al optimizar los archivos es recomendable ver las notas que indican en la documentación de RequireJS.

Si se quiere optimizar archivos individuales de javascript o no usamos RequireJS se puede utilizar la herramienta Closure Compiler, es muy sencilla, no hace falta instalar nada en nuestro equipo sino simplemente usar el servicio y da un resumen de la optimización que realiza.

Este ejemplo de introducción a RequireJS es muy sencillo y no muestra del todo el potencial que podemos conseguir con la utilidad r.js. La optimización de la lista de tareas con Marionette, otro ejemplo que hice, es más bastante más complejo y en el puede verse la mejora que podemos conseguir en cuanto a número de peticiones necesarias a realizar al servidor, tamaño en kilobytes del código descargado y tiempo en cargar de la página.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript

viernes, 5 de abril de 2013

Capturar errores de Javascript

Tener un sistema de logging para el código Javascript de una página está muy bien para depurar el código cuando las cosas van mal en el sentido de que no hacen o no se comportan como se espera. Pero a veces las cosas pueden ir peor que mal, esto es, si hay algún error de «compilación» en en código de javascript el navegador detiene la ejecución y por tanto dejan de emitirse las trazas. Si el error nos sucede en el entorno de desarrollo o pruebas en nuestro propio navegador nos daremos cuenta del error pero en un entorno de producción no ya que el código se ejecuta en el navegador del usuario.

Sin embargo, no todo está perdido, los navegadores proporcionan como último recurso la función «window.onerror» que será llamada cuando se detecte un error de compilación o ejecución que impida continuar ejecutando el código javascript. Lo que podremos hacer para tratar el error será limitado pero al menos con log4javascript podremos enviar al servidor ese mensaje para que podamos primeramente conocer que se está produciendo y luego resolverlo, de otra manera nos sería desconocido ya que el código javascript se ejecuta en un entorno al que no tenemos acceso, en el navegador del usuario.

En el siguiente ejemplo mostraré como enviar al servidor esos errores de javascript que se produzcan. Para conseguirlo usaremos una combinación de la librería log4javascript comantada en la entrada anterior y la función window.onerror. A continuación el contenido de una página con el contenido completo usando RequireJS:

En la siguiente imagen se puede ver la petición que hace log4javascript para enviar el error al servidor.


Aparte de la propia traza del error que envía log4javascript (aunque en la imagen anterior no es muy descriptiva) podemos obtener otra información relacionada con la petición http que se realiza como el navegador en el que se ha producido, sistema operativo y versiones de ambos aparte de cookies si las hubiese o la dirección IP. En esa URL deberemos tener algo que atienda la petición y saque a los logs del servidor el mensaje enviado. En caso de usar Java probablemente hagamos uso de un servlet, u otra cosa en función del framework web que usemos, y utilizaremos slf4j, log4j o logback para sacarlo al registro de trazas del servidor. El código completo de este ejemplo está alojado en mi repositorio de GitHub.

Referencia:

Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Optimizar módulos de RequireJS y archivos Javascript

jueves, 28 de marzo de 2013

Logging en Javascript con log4javascript

log4javascript
En esta serie de artículos que estoy escribiendo sobre varias librerías y herramientas relacionadas con el lenguaje de programación Javascript como RequireJS, Mustache y Backbone en esta ocasión voy a hablar de una librería de logging para javascript que también puede hacernos la vida más sencilla como programadores.

Sistemas de trazas hay muchos para Java y otros muchos lenguajes pero en el entorno de las aplicaciones web estos suelen usarse en la parte del servidor de las aplicaciones. Sin embargo, en el cliente también puede producirse errores y nos puede interesar tener información para averiguar la causa de forma que podamos solucionarlos más rápidamente o simplemente para tener un registro de lo que se ha ido haciendo en este caso en el cliente. Una librería de logging en el cliente también nos puede servir para tener información de errores en el navegador que de otra forma nos pasarían desapercibidos si solo tenemos trazas en el servidor, con la librería de trazas que explicaré en esta entrada podemos enviar las trazas de error al servidor de forma muy sencilla. Además, nos puede servir de utilidad en el momento de desarrollo del código javascript.

Por los motivos anteriores aunque no lo consideremos imprescindible nos puede resultar muy interesante la librería log4javascript. Los conceptos que emplea son muy parecidos a log4j con lo que si programamos en java aprenderemos fácil y rápidamente a usarla, en cualquier otro caso no nos llevará mucho tiempo aprender.

Lo primero que deberemos hacer es descargarla y una vez descomprimido el paquete incluirla en el código html de nuestra página con, haciendo uso de RequireJS:

Posteriormente deberemos usarla definiendo los appenders que determinarán a donde se envían las trazas, a los appenders les asociaremos un layout que determinará el formato de la traza y el nivel mínimo que ha de tener la traza («threshold») para ser emitido. log4javascript proporciona varios appenders según nuestras preferencias o necesidades:
  • AlertAppender: muestra las trazas usando la función alert del navegador.
  • AjaxAppender: realiza una petición ajax al servidor enviando la traza generada en el navegador, con este appender podremos tener el registro de lo que sucede en los clientes. Se ha de indicar el path de la URL que procesará las trazas en el servidor.
  • PopUpAppender: muestra las trazas en una ventana emergente en la que se pueden filtrar las trazas y en la que cada nivel aparece con un color distinto para reconocerlas más fácilmente.
  • InPageAppender: muestra la misma consola del PopUpAppender pero de forma incrustada en el pie de la página.
  • BrowserConsoleAppender: muestra los mensajes en la consola de depuración con los mensajes de javascript que incorporan los navegadores.
Con el siguiente bloque de código inicializamos el sistema de trazas, la variable log4j será la que utilicemos para emitir las trazas. En el ejemplo utilizamos el appender PopUpAppender con un layout que nos mostrará la hora, el nivel de la traza y el mensaje, el threshold del PopUpAppender es INFO con lo que todo mensaje con nivel menor prioridad como TRACE o DEBUG no aparecerán en el appender, para el caso de AjaxAppender el threshold será ERROR de modo que tampoco aparecerán en el las trazas INFO y WARN. Al emitir las trazas indicamos el mensaje más adecuado que consideremos más nos pueda ayudar y con el nivel de trazas según la importancia que tenga el mensaje, este nivel de trazas nos permitirá filtrarlos según su nivel en el popup:

El resultado que obtenemos en la consola emergente es el siguiente, los mensajes de nivel de trace y debug no aparecen por el threshold del appender PopupAppender.


Como los ejemplos de RequireJS y Mustache el código fuente completo lo puedes encontrar en mi repositorio de GitHib.

Referencia:

Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Capturar errores de Javascript

viernes, 22 de marzo de 2013

Introducción y ejemplo de Mustache


Mustache
Como comentaba en la Introducción y ejemplo sobre RequireJS el lado cliente están tomando cada vez más responsabilidad y peso en las aplicaciones. El lado cliente con los navegadores ya no se limitan a mostrar el html que se genera en el servidor de forma dinámica sino que son ellos mismos que obteniendo los datos en formato JSON probablemente mediante un servicio REST se encarga de transformar esos datos en el html que finalmente se ha de mostrar en la página. Generar el html en el cliente en vez de en el servidor tiene las siguientes ventajas:
  • Se reduce la carga del servidor.
  • La cantidad de datos devueltos es menor ya que el tamaño de la plantilla y los datos podrán ser menor que el html final generado por la combinación de ambos si una plantilla puede aplicarse varias veces sobre alguna lista de los datos.
Para transformar esos datos al html mediante una plantilla hay diferentes librerías que proporcionan esa funcionalidad entre ellas Mustache y Handlebars. Mustache es más simple que Hadlebars y Handlebars es un superconjunto de Mustache por lo que si tenemos una plantilla en Mustache podremos utilizarla en Handlebars. En esta entrada comentaré un ejemplo simple y sencillo con las posibilidades de Mustache.

Mustache se caracteriza por su simplicidad evitando incluir lógica en las plantillas, es decir, sin sentencias if y bucles aunque algunas etiquetas proporcionan la misma funcionalidad. El hecho de no incluir lógica en las plantillas hace que estas sean sencillas, fáciles de desarrollar y de mantener además de obligar a no mezclar conceptos lo que hace que el código sea «limpio».

La esencia de Mustache al igual que otros sistemas de plantillas es que por un lado tenemos los datos que forman parte del modelo y por otro lado la plantilla que forma parte de la vista, juntando ambos obtenemos un resultado.

Veamos como se traduce todo esto en código javascript. Lo primero y más sencillo son las variables que en la plantilla se indican entre {{ }}, estos corchetes con forma de mostacho le dan nombre a la librería, la variable es sustituida por el valor proporcionado en el modelo:


Secciones

Otra posibilidad de Mustache con las secciones que se indican con un # delante de la variable. Si la variable de una sección es false, tiene valor null o es un array vacio, esa sección se omite en el resultado. De esta forma una sección puede hacer de lo que en un lenguaje de programación sería una condición.


Secciones lista

En el caso de hacer una sección en el que la variable sea una array o lista, la sección recorrerá cada uno de los elementos de la lista y generará un contenido por cada elemento. Esto nos proporciona la funcionalidad de un bucle.


Parciales

Si no queremos tener una plantilla muy grande o queremos rehusar cierta parte en varias plantillas la podemos dividir usando parciales. Los parciales se indican con el caracter > y son una forma de llamar a un trozo de una plantilla. En la plantilla los parciales son sustituidos por su correspondiente código del mapa de parciales y la plantilla se procesa como si fuese una completa. Este es el mismo ejemplo de la sección lista pero usando parciales:


Compilación

Para una mayor eficiencia sobre todo en dispositivos móviles las plantillas pueden compilarse con:


Esto es lo básico de Mustache, tiene alguna posibilidad más como las funciones donde se puede añadir algo de lógica, también están las secciones invertidas que se indican con ^ y generan resultado si la variable de la sección es null, false o vacía, es decir, lo contrario de una sección normal. Por defecto los caracteres html de una variable son escapados pero puede evitarse con tres llaves {{{ }}} o un & antes del nombre de la variable. También puede cambiarse el delimitador de Muchache, los {{ }}, por otra cadena pero será poco habitual que lo necesitemos.

La otra alternativa que comentaba es Handlebars con la que si tenemos una plantilla de Mustache podemos utilizarla en Handlebars sin ningún cambio ya que Handlebars soporta todas las características de Mustache y añade algunas otras. Las principales diferencias entre Mustache y Handlebars es que Mustache puede ser usada desde diferentes lenguajes como Java, Python, Ruby, D, .NET, PHP, y alguno más que puede verse en la página del proyecto, Handlebars solo se puede utilizar usando javascript. Dado que Mustache puede ser utilizado con Java puede ser una alternativa a librerías como FreeMarker de esta manera podemos hacer uso de la misma librería de plantillas tanto en el servidor como en el cliente de forma que evitemos tener que aprender y conocer varias tecnologías que hacen lo mismo y aprovechemos mejor lo que conocemos. Otra diferencia es que Handlebars añade el concepto de funciones de ayuda («helpers») mediante los cuales se puede añadir lógica si nos es necesario y aunque puede facilitarnos ciertas tareas no conviene abusar de ello ya que puede hacer que las plantillas dejen de ser tan simples y empiecen a no ser fáciles de mantener.

El código fuente completo de este ejemplo los puedes encontrar en mi repositorio de GitHub.

Referencia:

Introducción y ejemplo de RequireJS
Logging en Javascript con log4javascript
Capturar errores de Javascript

viernes, 15 de marzo de 2013

Introducción y ejemplo de RequireJS

RequireJS
Las páginas web ha evolucionado mucho desde sus inicios en los que eran simples páginas estáticas hechas con el lenguaje de marcas html, podían contener enlaces e imágenes. Posteriormente adquirieron capacidad de cambiar a través un lenguaje de programación que en el servidor genera el código html de forma dinámica basándose en la información que el usuario podía enviar en un formulario, también se incorpora cierta programación en el cliente con javascript. Con las nuevas versiones del estándar html, los avances de los navegadores y una explosión de dispositivos móviles de gran capacidad las aplicaciones están evolucionando hacia el cliente, haciéndose cada vez más complejas en el lado del navegador del usuario y adquiriendo resposabilidades que antes tenía la aplicación en el lado del servidor. Cada vez hay más librerías y frameworks javascript que tratan de resolver problemas específicos de las aplicaciones de internet. Entre estas librerías algunas de las más conocidas son, muy resumidamente:
  • jQuery: para manejar los elementos de la página.
  • mustache: a partir de una plantilla y unos datos genera un resultado.
  • underscore: proporciona ciertas utilidades bastante comunes que el lenguaje javascript no proporciona.
  • Backbone: da un modelo MVC para el desarollo de las aplicaciones.
Por supuesto, para cada área hay varias opciones entre las que se puede elegir, estas no son las únicas librerías hay muchas más alternativas (hadlebars, prototype, agularjs, mootools, ...) que en esencia proporcionan la misma funcionalidad que las anteriores. A medida que vamos haciendo uso de más librerías, archivos javascript y que estas pueden tener dependencias unas sobre otras se hace necesario algo que permita gestionar esas relaciones entre las librerías para que el código javascript se cargue en el orden adecuado y funcione correctamente. Aquí surge RequireJS, que además de gestionar esas dependencias también nos proporciona otras ventajas:
  • La carga de los archivos javascript se hace de forma asíncrona evitando el resto del contenido de la página se bloque hasta que los js de la página se carguen.
  • Permitirnos optimizar los archivos javascript juntándolos en uno solo de forma que sean necesarias menos peticiones al servidor y a la vez minificándolos para hacer que ocupen menos y la transferencia sea más rápida.
  • Se evita contaminar el ámbito global de javascript evitando posibles conflictos entre archivos javascript.
Algunas de estas ventajas hacen que la página cargue más rápido que es algo que el buscador de Google tiene muy en cuenta para el posicionamiento en los resultados de búsqueda.

Con RequireJS los archivos javascript se organizan en módulos y estos pueden tener dependencias sobre otros, todos los archivos javascript necesarios son cargados por RequireJS de forma asíncrona. Haciendo uso de RequireJS en la página web solo será necesario incluir un único javascript, que será el de RequireJS, en la propia etiqueta script y con el atributo data-main le indicaremos el módulo del que va a hacer uso la página. El resto de módulos se cargarán como dependencias del módulo que especifiquemos en el atributo data-main.

En el módulo inicial que carga la página, main.js, hacemos uso de la función require cuyos parámetros son un array con la lista de dependencias sobre otros módulos y una función que será llamada cuando RequireJS haya cargado todos los módulos indicados en la lista, en este caso solo uno. Por cada dependencia la función que se llama cuando todos los módulos se han cargado recibe un objeto como parámetro, de esta manera RequireJS es como evita contaminar el ámbito global ya que no son necesarias definiciones en el ámbito global.

En el ejemplo del módulo main.js en la función require se indica una dependencia sobre el módulo figuras. El módulo de las figuras contiene la lógica de esta simple aplicación que es calcular el área de un cuadrado y un triángulo y mostrar el resultado en un diálogo emergente. Una vez que todas las dependencias del módulo de la aplicación, en este caso solo una, han sido cargadas por RequireJS se llama a la función callback del módulo de la aplicación con la referencia del módulo de figuras.

El módulo figuras no tiene ninguna dependencia con lo que el array de dependencias no es necesario y solo se indica la función de inicialización del módulo en la función define. Este módulo define los prototipos de dos objetos, un cuadrado y un triángulo, con un método cada una de ellas que permiten calcular su respectiva área. El retorno de la función de inicialización del módulo es importante ya que lo devuelto por esta función es lo que recibirán como referencia los módulos que dependan sobre el módulo de figuras.

El resultado es este:


Las funciones require y define son similares pero si un módulo va a ser usado por otros se ha de usar la función define, sino va a ser usado por otros se puede usar la función require.

En posteriores entradas hablaré y pondré un ejemplo de otros temas relacionados con javascript como mustache, backbone, REST, logging, optimización, ... que nos pueden ayudar mucho a hacer mejores aplicaciones, más complejas, de forma más sencilla, con menos errores y más rápidamente. Este artículo sobre RequireJS solo es el primero en el que se basarán el resto que escribiré sobre javascript.

El código fuente completo de este ejemplo de RequireJS lo puedes encontrar en mi repositorio de GitHub.

Referencia:

Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript