Una sinfonía en C#

Un pequeño aporte a la comunidad de habla hispana.

Bower: manejador de paquetes para Javascript

A medida que las aplicaciones crecen, crecen también en dependencias y muchas veces la tarea de comenzar una aplicación es tediosa y repetitiva al tener que agregar una y otra vez las mismas referencias o no.

Bower logo

Primero que nada, tener Nodejs instalado

Sí, Bower es un paquete de Nodejs, así que una vez que tenemos Nodejs instalado, ejecutamos el siguiente comando:

npm install -g bower

CERT_UNTRUSTED Error

Si esto ocurre lo más simple es ejecutar el siguiente comando

npm config set ca "" 

Si esto no funciona acá hay un par de opciones más

También es necesario git

Bower permite instalar paquetes desde cualquier repositrio git (incluso uno nuestro, remoto lo local) pero necesitamos tener git instalado y en el path para que Bower lo encuentre.

Ahora sí, bower instalado, empecemos

Una vez que tenemos Bower instalado podemos hacer lo mismo que hacemos con el comando npm de Nodejs, es decir, solicitar paquetes.

Entonces vamos a la consola y ejecutamos

bower install requirejs

image

si revisamos el directorio desde donde ejecutamos el comando vamos a ver que Bower creó una carpeta bower_components y puso el paquete ahí (lo que hay en el paquete depende de la definición de quien lo creó)

Cambiando el directorio de instalación

Esto es simple, creamos un archivo con el nombre .bowerrs (si, un archivo sin nombre con extensión bowerrc) y colocamos lo siguiente dentro

{	
"directory": "scripts"
}

Entonces ejecutamos de nuevo el comando y vemos que Bower pone todo dentro de la carpeta scripts

Automatizando tareas comunes

Una cosa interesante es tener un archivo con varias dependencias que siempre usamos y usarlo de base para instalar diferentes paquetes y versiones en nuestra aplicación, esto es simple. Creamos un archivo con el nombre bower.json y colocamos dentro lo siguiente

{	
"name": "app", "dependencies": {"backbone": null, "jquery": null, "requirejs": null}
}

Ahora con estos dos archivos en nuestro directorio no nos queda más que ejecutar bower install y listo (el null en cada componente indica la versión, en este caso es la última).

image

Un detalle interesante es que instaló underscorejs sin que lo pidamos, esto ocurre porque backbone tiene definido en su archivo de configuración de Bower que depende de underscore.

Esto es un buen ejemplo de un archivo de configuración

{
  "name"          : "backbone",
  "version"       : "1.1.2",
  "main"          : "backbone.js",
  "dependencies"  : {
    "underscore"  : ">=1.5.0"
  },
  "ignore"        : ["backbone-min.js", "docs", "examples", "test", "*.yml", "*.map", ".html", "*.ico"]
}

Como verán se pueden definir muchas cosas, acá podemos encontrar una referencia completa.

Entonces, a partir de ahora podemos tener nuestros archivos de configuración comunes para las aplicaciones y dejar que Bower haga todo por nosotros, o si tenemos un proyecto con dependencias de terceros simplemente agregamos en el código los archivos de configuración de Bower para que cada uno los instale.

Hasta la próxima.

Tips de Javascript: Arrays 2

Para completar por ahora algunas pequeñas cosas sobre arrays en Javascript, vamos a ver unos detalles sobre cómo crearlos.

Siempre usar la notación literal []

image

El resultado es el mismo si usamos [1,2,3] o new Array(3)

image

Pero, no es lo mismo [3] que new Array(3) como podemos ver, mientras que [3] es coherente con el primer ejemplo (crea un array con un elemento de valor 3) new Array(3) crea un array de tres elementos vacíos!

image

Esto es cierto, pero si el elemento que pasamos al constructor no es un entero se comporta igual que [3]

por lo tanto

Es conveniente usar siempre la notación literal ya que el constructor de la clase Array tiene un comportamiento extraño (al menos para mí)

Hasta la próxima.

Tips de Javascript: Arrays

Vamos a ver algunas pocas características sobre arrays en Javascript, cortitas, pero interesantes.

Los arrays son objetos

Esto es obvio, en un punto todo es un objeto, pero en el caso de los arrays no hablamos de un objeto array como en C#, sino que un array es un objeto y cuando le agregamos elementos lo que estamos agregando son miembros del array, por ejemplo

var a = [1, 2, 3];

Esto no nos dice mucho, pero esto nos da una pista:

var a = [1, "hola", function() { console.log("hola");}];

Es por eso que no importa el tipo de cada elemento del array.

Podemos decir que un array es un objeto en el cual sus propiedades tienen por nombre el número de índice del array, es decir 0, 1, 2, 3; pero no podemos acceder a las propiedades con el punto (.) porque no está permitido que un identificado empiece con el mismo (a.1) , por eso hacemos

a[2]();

y es válido.

Las mismas reglas que se aplican a un objeto se aplican a un array

Claro, son objetos, es por eso que podemos iterar propiedades de un objeto del mismo modo que lo hacemos con un array como vemos en este post.

Hasta la próxima.

Tips de javascript: Por qué usar hasownproperty al iterar un objeto con for?

Hay una linda forma de obtener los miembros de un objeto cualquiera en Javascript de la que ya hablé, que básicamente es así:

var persona = {nombre: "leonardo", blog: "http://leomicheloni.com"};
for(var prop in persona){
	console.log(prop + " =  " + persona[prop]);
}

Y ocurre lo siguiente:

image

Perfecto, el problema es si por algún motivo agregamos funciones o propiedades a objetos de Javascript que pueden estar relacionados con nuestro objeto, es decir, imaginemos que queremos hacer una función en Object que retorne un string con cierto formato, así:

Object.prototype.format = function(){
	return "{"  + this + "}";
};

(de más está decir que es un ejemplo) lo que pasa ahora si corremos el código anterior es lo siguiente:

image

Esto puede pasar no sólo si agregamos funciones a Object sino que también si lo hacemos a String, o Array dependiendo del caso;

hasOwnProperty

Entonces la función hasOwnProperty nos permite saber si un miembro tal es del objeto en cuestión o de uno de sus prototipos, el ejemplo anterior sería así:

 

Object.prototype.format = function(){
	return "{"  + this + "}";
};

var persona = {nombre: "leonardo", blog: "http://leomicheloni.com"};
for(var prop in persona){
	if(persona.hasOwnProperty(prop)){
		console.log(prop + " =  " + persona[prop]);
	}
}

y santo remedio, ahora funciona.

image

Nos leemos!

Manejando dependencias en Javascript con RequireJs

A medida que nuestra aplicación crece en número de archivos Javascript y, más aún, si nuestra aplicación es una “single page application” (es decir todo ocurre en el mismo HTML y se va cargando y descargando contenido) y, por supuesto, usamos módulos para separar la aplicación en partes lógicas, empieza a ser complicado manejar algunos problemas como:

  1. Referencias que se cargan tarde
  2. Referencias que se cargan más de una vez
  3. Referencias que se cargan y no se utilizan

Es decir, nuestro proyecto tiene un tamaño interesante, unas cuantas referencias (bibliotecas, funcionalidad de diferentes partes de la pantalla, etc.) y nos encontramos con problemas de este tipo:

  1. Errores por referencias no cargadas
  2. Sobre-escritura de métodos por librerías que se cargan más de una vez, por ejemplo un plugin de jQuery que deja de andar cuando se carga jQuery una vez que cargó el plugin.
  3. Lentitud de la aplicación por esperar cargar cosas innecesarias o que aún no se necesitan, por ejemplo si ponemos todo en el la sección header del html para que se cargue siempre y evitar el problema 1.
  4. Crecimiento del costo de ancho de banda y peticiones al servidor para cargar referencias que no siempre se usan, imaginen que nuestra aplicación tiene una sección de carga de pedidos con un montón de validaciones pero no siempre se activa esa parte, cargar todo el código relativo a esa funcionalidad siempre no es lo más inteligente.
  5. etc.

RequireJs, una biblioteca para manejar dependencias en Javascript

Esta pequeña biblioteca nos ayuda solucionar estos problemas, vamos a enumerar alguna de sus características:

  • Carga dinámica de dependencias
  • Descarga automáticas de dependencias
  • Manejo de timeouts y carga de fallbacks

Adicionalmente podemos, gracias a una de sus utilidades logar

  • Minificación
  • Bundling

Primer ejemplo con Requirejs

Empecemos por lo más simple, creamos un HTML y agregamos la referencia a requirejs

<html>
<head>
<script type="text/javascript" src="http://requirejs.org/docs/release/2.1.9/minified/require.js"></script>
</head>
<body></body>
</html>

Primero indicamos a requirejs dónde empezar

Bien, este tag script va a ser la única referencia que vamos a tener, de todo lo demás se va a encargar requirejs, para eso tenemos que decirle cuál es el archivo por el cual va a comenzar nuestra aplicación, simplemente agregamos al mismo tag script un atributo

<script type="text/javascript" data-main="main" src="http://requirejs.org/docs/release/2.1.9/minified/require.js"></script>

con el atributo “data-main” le decimos a requirejs qué archivo es el punto de entrada de nuestra aplicación, como verán en este caso es “main.js” (el js siempre se omite), ahora dentro de nuestro archivo main.js hacemos lo siguiente:

require([], function(){
	console.log("hola require");
});

Bien, si lo ejecutamos imprime en la consola del navegador, vamos a explicar qué es esto

La función require

Esta función la vamos a usar cuando queramos cargar un módulo, el primer parámetro (que ahora es un array vacío) indica la dependencias, es decir, de qué otro módulos depende éste para correr, por ahora nada, el segundo parámetro es un callback que se ejecuta cuando todas las dependencias han sido resueltas, es decir si main.js depende de a.js y éste a su vez de b.js requirejs se va a encargar de cargar estas dependencias y asegurarse que están disponibles antes de llamar al callback (incluso si ya están cargadas no lo hace nuevamente) excelente, vamos a verlo.

main.js

require(["a"], function(){
	console.log("soy main");
});

a.js

define(["b"], function(){
	console.log("soy a");
});

En lugar de usar require() usamos define() ya que estamos definiendo un módulo, no pidiendo que se cargue, de eso se va a encargar requirejs cuando resuelva las dependencias.

b.js

define([], function(){
	console.log("soy b");
});

Ejecutamos el código y vemos el orden de resolución de dependencias

image

Utilizando dependencia

Hasta ahora comprobamos el orden de carga y no mucho más, lo interesante es tener funcionalidad que se cargan y poder utilizar los objetos que define cada módulo, bien, para eso cambiamos un poco el ejemplo:

main.js

require(["perro"], function(Perro){
	var roger = new Perro();
	roger.ladrar();
});

perro.js

define([], function(){
	var Perro = function(){
	};
	
	Perro.prototype.ladrar = function(){
		console.log("guauu!!");
	};
	
	return Perro;
});

lo corremos y…

image

Básicamente en main.js definimos la dependencia y luego la recibimos como parámetro del callback, dentro de perro.js tenemos que hacer return del objeto que queremos que el módulo reciba.

Cargando bibliotecas externas con Requirejs

Por supuesto que podemos cargar dependencias de terceros, la primera que viene a la mente es jQuery, pero como no es práctico copiarnos en código dentro de un módulo lo que hacemos es configurar requirejs para que cuando alguien le pida jQuery sepa qué hacer, del siguiente modo:

//configuramos requirejs para que cuando alguien pida jquery cargue la dependencia
requirejs.config({
	"paths": {
		"jquery": "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min",
	}
});

require(["perro", "jquery"], function(Perro, $){
	var roger = new Perro();
	var saludo = roger.ladrar();
	$("body").append("<strong>" + saludo + "</strong>");
});

(modifiqué el método ladrar para que retorne un saludo)

image

básicamente llamamos al método config de requirejs y le decime qué hacer cuando le pidan jQuery.

jQuery soporta requirejs

Como muchas otras bibliotecas populares jQuery está preparada para soporta requirejs, de qué forma? bueno, si miramos el código jQuery podemos descubrirlo

	if ( typeof define === "function" && define.amd ) {
		define( "jquery", [], function () { return jQuery; } );
	}

Como vemos al final del código de jQuery esta línea se fija si existe requirejs y si es así define un módulo llamado jquery (utiliza otra sobrecarga del método define para ello)

Bien, es todo por esta vez, hay mucho más para ver, como definir dependencias entre bibliotecas de terceros y demás, pero lo dejamos para la próxima. Enjoy.