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