Crear un archivo robots.txt

Como sabréis, los motores de búsqueda se sirven de «robots», programas que indexan las páginas web alojadas en un servidor, para que estas puedan ser localizadas por el buscador (Google, yahoo…). Por defecto todos los robots tendrán el acceso permitido y podrán ver todo lo que tengamos alojado en la raíz de nuestro servidor, y en muchos casos eso no nos interesa.

¿Cómo arreglamos esto? Con el robots.txt, archivo que generalmente guardaremos en la raíz de nuestro servidor. En él podemos incluir qué directorios queremos desactivar y para qué bots. Un ejemplo simple: este robots.txt bloquería todo el directorio raíz (con todos sus subdirectorios) para todos los bots:

User-agent: *
Disallow: /
#y si quieres poner comentarios, que no serán interpretados por los bots/crawler basta con comenzar la línea con este carater#

Las utilidades del robots.txt pueden ser más de las que a priori imaginas. Obviamente evita que se indexe contenido que quieras mantener oculto o protegido, pero también te permite evitar que se indexe contenido duplicado (recuerda, el contenido duplicado rebaja tu page-rank), impedir la idexación de bots no deseados (no todos los bots son de buscadores legítimos) y si tienes un site con mucho tráfico evitará una carga de trabajo extra sobre el servidor.

Vamos a ir por partes, explicando algunas peculiaridades.

La primera es que puedes incluir varios Disallow bajo un mismo user agent, pero no varios user agent encima de un disallow.

#así sí
User-agent: bingbot
Disallow: /wp-content/
Disallow: /js/

User-agent: Googlebot
Disallow: /wp-content/
Disallow: /js/

#así NOOOOOOO
User-agent: bingbot
User-agent: Googlebot
Disallow: /wp-content/
Disallow: /js/

En cuanto al uso de comodines y expresiones regulares… puedes usarlos específicamente para
Googlebot y Slurp (el bot de Yahoo). Por lo que he leído el resto no las aceptan, así que no lo intentes usar de forma general ya que muchos crawlers no lo entenderán y sí indizarán esa página.

#esto bloquería todos los archivos .js para Slurp
User-agent: Slurp
Disallow: /*.js?

#esto lo bloquería para Slurp y Googlebot, pero el resto no lo entenderían e indizarían
User-agent: *
Disallow: /*.js?

Si tienes un sitemap en el servidor puedes incluirlo en el robots.txt con una simple línea:

Sitemap: http://miservidor/sitemap.xml

Y, como te decía arriba, también puedes reducir la frecuencia de rastreo para que los bots no estén entrando todo el día. Si tienes una web con muchas visitas pero pocas actualizaciones basta con especificarlo con Crawl-delay. Eso sí, no todos los bots lo soportan:

#así le dirías al robot de Bing que sólo entre cada 45 días
User-agent: bingbot
Crawl-delay:45

También se puede usar la palabra Allow en lugar de Disallow… pero por defecto todos los directorios y archivos están permitidos y, además, no todos los bots lo van a entender. Así que mejor Disallow para restringir zonas que Allow para habilitarlas.

Recursos gratuitos para programación web y móvil

Vamos con una minientrada con algunas páginas con recursos totalmente de gratis para vuestros desarrollos (La entrada es de 2013, pero a octubre de 2019 la he recordado y he decidido actualizarla quitando algunos enlaces que ya no funcionan y añadiendo alguna más):

  • HTML5 UP!: Una web, del creador de la anterior, que nos ofrece una, de momento, pequeña colección de plantillas responsivas en HTML5 y CSS3. Como la anterior, totalmente gratis.
  • Web Resources Depot: En este caso se trata de un blog que recoge a diario diversos recursos gratuitos publicados en distitnas páginas.
  • Webappers:Similar a Web Resources Depot, una web que publica a diario recursos publicados en otras páginas.
  • Google Fonts: Si andas buscando tipografías que además no te den problemas de compatibilidad entre navegadores, este servicio de Google (de momento gratuito) te puede solucionar la papeleta. Dispone de momento de más de 200 tipografías para tu uso y disfrute.
  • Font Squirrel: Por no dar todo el poder a Google, otra alternativa puede ser Font Squirrel, otra página de tipografías gratuitas para tu web.
  • Easel.ly: Esta página nos permite crear infografías on-line de manera sencilla y exportarlas a .jpg, con multitud de plantillas.
  • Online OCR: Hay clientes muy zotes, todos los sabemos. Algunos te envían los textos escaneados en un pdf del que no puedes copiar ni pegar (¿lo imprimieron y escaneron?). Esta web te soluciona la papeleta devolviéndote el resultado en múltiples formatos. Tiene limitaciones en su plan gratuito, pero permite trabajar bastante.
  • Bounce: ¿Quieres hacer una captura de una página completa y añadirle notas por encima de manera fácil? Esta herramienta te lo permite. Seleccionas una url, la carga… y listo.
  • Pexels: Sitio web con fotografías gratuitas del que hablamos en un artículo previo.
  • Unsplash: Sitio web con fotografías gratuitas del que ya hablamos en un artículo previo.
  • Freebiesbug: Plantillas, iconos y otros recursos web.

Una serie de utilidades para dar un toque más elegante y funcional a tus webs.

Comprobar si un número es par o impar con PHP

El otro día me preguntaron si había alguna función de PHP que devolviera si un número es par o impar, tipo is_odd, is_even o similar. Realmente es una comprobación que puedes hacer con una línea de código, así que no existe una función que lo haga. Si lo que quieres es simplemente imprimir en pantalla par e impar la solución es simple (supongamos que el número a comprobar está en la variable $number):

echo ($number % 2 ? 'Impar' : 'Par');  

Tan solo necesitas la operación de módulo, que devuelve el resto de la división entera del número entre 2. Como el resultado en caso de que sea par será 0 este será interpretado en los condicionales o en un operador ternario como un FALSE.

¿Lo queréis como función que devuelva true o false? Ok, es simple. Esta es una función que devuelve TRUE si es impar y false si es par :

function esImpar($number){
    return $number % 2;
}

Y si te quieres ir de guay hasta puedes usar el operador & a nivel de bit para hacerlo (para quedar más pro)

if($number & 1){  
    echo 'Impar';  
}else{  
    echo 'Par';  
} 

Ale, ya tenéis por ahí tres soluciones para comprobar si un número es par o impar.

Poblar un combo dinámicamente con jQuery y JSON

Es habitual que, creando formularios, nos encontremos con la situación de tener dos combos (o campo select si lo preferís) y que uno tenga que cargar/modificar sus datos según el resultado seleccionado en el otro, de forma dinámica. Esto es posible con Javascript, y muy cómodo si utilizamos JSON y jQuery.

Os planteo un ejemplo simple: tenemos dos combos, uno con provincias y otro con ayuntamientos. El marcado HTML va a ser más o menos tal que así:

<select id="provincias" name="provincias">
  <option value=""></option>
  <option value="1">A Coruña</option>
  <option value="2">Lugo</option>
  <option value="3">Ourense</option>
  <option value="4">Pontevedra</option>
</select>
<select id="poblaciones" name="poblaciones" disabled="disabled">
</select>

Como véis, al momento de cargar la página el campo provincias tendrá las cuatro provincias gallegas, y el campo poblaciones estará desactivado. ¿Ahora qué necesitamos? Pues primero necesitamos un script que nos saque las poblaciones de la base de datos y nos las envíe como un JSON. Cualquier lenguaje de lado del servidor nos vale, para el ejemplo va a ser PHP (pero vamos, que podría aplicarse con Java, Ruby, node.js, Python…). Crearemos un script llamado getPoblacionesJson.php

<?php
include 'conexionbd.php';
if ($mysqli -> multi_query("CALL sp_GetPoblaciones(" . $_GET['pr'] . ")")) {
	$poblaciones = array();
	do {
		if ($result = $mysqli -> store_result()) {
			while ($fila = $result -> fetch_assoc()) {				
				$poblaciones[$fila['Id']] = $fila['Nombre'];
			}
		}
	} while($mysqli->next_result());
	print_r(json_encode($poblaciones));
}
?>

En este caso veis que lo que hacemos es llamar a un procedimiento almacenado que nos devuelve las provincias, recorremos el resultado y vamos guardándolo en un array. Finalmente lo convertimos a JSON y lo imprimios para que lo recoja la función de Javascript. Si os estáis preguntando cómo va el procedimiento almacenado, es una simple select en MySQL, tal que así:

DELIMITER $$
CREATE PROCEDURE sp_GetPoblaciones(IN provincia int)
begin
	SELECT Id, Nombre FROM poblaciones WHERE (provincia is null or IdProvincia = provincia) ORDER BY Nombre;
end $$
DELIMITER ;

Ok, tenemos entonces el script del servidor, el marcado y el procedimiento en la base de datos. ¿Qué nos queda? Pues el Javascript, vitaminado con jQuery para ganar productividad:

$("#provincias").change(function() {
	$("#poblaciones").empty();
	$.getJSON('http://localhost/getPoblacionesJson.php?pr='+$("#provincias").val(),function(data){
		console.log(JSON.stringify(data));
		$.each(data, function(k,v){
			$("#poblaciones").append("<option value=\""+k+"\">"+v+"</option>");
		}).removeAttr("disabled");
	});
});

La idea es simple: Si se registra algún cambio en el combo de provincias vaciamos el combo de poblaciones y lo rellenamos con los nuevos datos, obtenidos mediante la función getJSON() y que recorreremos con each() como un conjunto de claves/valores. Finalmente, por si está desactivado, lo reactivamos. He hecho un console.log por si queréis ver cómo funciona la cosa en la consola de javascript de Chrome o del Firebug.

Espero que os sirva de ayuda esta entrada para trabajar con combos dinámicos.

Diferencias entre isset(), empty() e is_null() en PHP

Entre las múltiples funciones que existen en PHP para testear los valores de una variable encontramos tres que resultan de gran ayuda para conocer si una variable está definida y/o es nula, que son isset(), empty() e is_null(). Rehaciendo código de alguna gente en mantenimientos o actualizaciones de proyectos me he encontrado con dos hechos:

  1. Muchos no las usan (y luego vienen los errores por usar una variable vacía)
  2. Muchos no tienen muy claro cómo y cuándo usarlas

La cosa es muy sencilla si se explica bien. Vamos a ver en qué consisten las tres, y veréis qué rápido lo entendéis:

  • isset(): Determina si una variable ha sido definida y no es nula. Devuelve FALSE en caso de le pasemos una variable sin definir, una variable definida pero sin valor o con el valor puesto a null, y en el resto de casos devuelve TRUE.
  • empty(): Determina si la variable tiene un valor vacío, por llamarlo de alguna forma. En este caso devuelve TRUE en muchos supuestos: una cadena vacía (es decir «», si es una cadena con un espacio en blanco tal que » » devolverá FALSE), un número 0 (sea tanto un entero, un float o una cadena con el número cero tal que «0»), una variable con el valor FALSE, una variable con el valor NULL, una variable definida pero sin valor y un array vacío. Al contrario que isset(), no puede evaluar variables que no hayan sido definidas.
  • is_null(): En cierto modo es la complementaria a isset(), ya que devuelve TRUE en caso de que la variable sea NULL o que sea una variable definida pero sin valor, y en el resto de los casos FALSE. La diferencia es que no puede evaluar variables que no estén definidas, provocará un error.

Como podéis ver no es especialmente complicado comprender el funcionamiento de estas tres funciones, y su uso os salvará de muchos quebraderos de cabeza. Por ejemplo trabajando con variables pasadas por formularios o recogidas de una tabla de base de datos que acepte nulos, que todavía hay gente que va a lo loco, así, sin comprobación ni condón… y luego vienen las rupturas en el código.

Display inline-block en Explorer 6, Explorer 7 y Explorer 8

Si maquetáis web es posible que utilizáseis alguna vez la propiedad display:inline-block en vuestro CSS a la hora de posicionar divs o elementos de lista, ya que funciona de una forma muy cómoda. ¿Problemas de usarla? Que en en las versiones anteriores a Explorer 8 no va (este inclusive).

Actualmente, por suerte, casi nadie tiene Explorer 7 (y menos Explorer 6) y los que queden se irán al guano cuando Microsoft deje de dar soporte a XP en 2014, pero todavía hay varios Windows Vista con Explorer 8 rulando por ahí, además también hay administraciones, clínicas o empresas con equipos arcaicos y sin actualizar. ¿Solución? Algunos te dirán «no la uses»… pues no, hay un simple hack, que podéis ver en el ejemplo:

elementoAPosicionar {
    display: inline-block;
    *display: inline;
    zoom: 1;
}

Con esto usamos un Safe CSS Hack para que IE7 interprete bien nuestro CSS. Otra posibilidad es que no funcione por culpa de la declaración del DOCTYPE (Explorer es muy puñetero). Si pasáis de Explorer 7 y sólo os preocupa el 8, basta añadir esto al principio del archivo HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Y creo que si lo declaráis como HTML5 con esta cabecera también funciona:

<!DOCTYPE html>

Por suerte a partir de Explorer 9 muchas de estas cosas se han ido estandarizando, y de momento en Explorer10 lo único que me ha fallado ha sido una animación CSS3, lo cual respecto a hace años es un enorme avance para los chicos de Microsoft. Igual en IE12 ya no hace falta hacer un CSS específico para Explorer.

Enviar un email con PHPMailer usando una cuenta de Gmail

Ya hace un tiempo hablamos aquí de cómo enviar correos desde un script de php usando PHPMailer. He decidido hacer una serie de artículos ampliando un poco más el tema.

Una cuestión que puede ser interesante, sobre todo para aquellos que a lo mejor están en un hosting gratuito y no tienen cuentas de correo vinculadas a su dominio, es utilizar una cuenta de Gmail para enviar los correos. Ya que Gmail nos permiter usarlo como cualquier otro correo SMTP esto es factible.

Configurar PHPMailer para usar Gmail es simple, y podéis ver cómo se haría en el siguiente ejemplo (va comentado línea a línea):

/*Lo primero es añadir al script la clase phpmailer desde la ubicación en que esté*/
require '../class.phpmailer.php';

//Crear una instancia de PHPMailer
$mail = new PHPMailer();
//Definir que vamos a usar SMTP
$mail->IsSMTP();
//Esto es para activar el modo depuración. En entorno de pruebas lo mejor es 2, en producción siempre 0
// 0 = off (producción)
// 1 = client messages
// 2 = client and server messages
$mail->SMTPDebug  = 0;
//Ahora definimos gmail como servidor que aloja nuestro SMTP
$mail->Host       = 'smtp.gmail.com';
//El puerto será el 587 ya que usamos encriptación TLS
$mail->Port       = 587;
//Definmos la seguridad como TLS
$mail->SMTPSecure = 'tls';
//Tenemos que usar gmail autenticados, así que esto a TRUE
$mail->SMTPAuth   = true;
//Definimos la cuenta que vamos a usar. Dirección completa de la misma
$mail->Username   = "tucuenta@gmail.com";
//Introducimos nuestra contraseña de gmail
$mail->Password   = "tucontraseña";
//Definimos el remitente (dirección y, opcionalmente, nombre)
$mail->SetFrom('tucuenta@gmail.com', 'Mi nombre');
//Esta línea es por si queréis enviar copia a alguien (dirección y, opcionalmente, nombre)
$mail->AddReplyTo('replyto@correoquesea.com','El de la réplica');
//Y, ahora sí, definimos el destinatario (dirección y, opcionalmente, nombre)
$mail->AddAddress('destinatario@sucorreo.com', 'El Destinatario');
//Definimos el tema del email
$mail->Subject = 'Esto es un correo de prueba';
//Para enviar un correo formateado en HTML lo cargamos con la siguiente función. Si no, puedes meterle directamente una cadena de texto.
$mail->MsgHTML(file_get_contents('correomaquetado.html'), dirname(ruta_al_archivo));
//Y por si nos bloquean el contenido HTML (algunos correos lo hacen por seguridad) una versión alternativa en texto plano (también será válida para lectores de pantalla)
$mail->AltBody = 'This is a plain-text message body';
//Enviamos el correo
if(!$mail->Send()) {
  echo "Error: " . $mail->ErrorInfo;
} else {
  echo "Enviado!";
}

Esencialmente es casi lo mismo que viene en los DOCS que acompañan a los archivos, pero traducido.

Espero que os sirva. Próximamente más PHPMailer, y más programación web.

Detectar Internet Explorer con PHP

Es habitual que algunas versiones de Internet Explorer den la tabarra al ser un navegador que no sigue los estándares. Tranquilos, don’t worry. Podéis detectar con PHP si el navegador es Explorer y, dependiendo del resultado, mostrar una maquetación u otra. La función es simple:

<?php
$browser = getenv("HTTP_USER_AGENT");
if (preg_match("/MSIE/i", "$browser"))
{
    //Lo que toque hacer con el Explorer
}
else
{
   //El resto
}
?>

Claro que hay que reconocer que IE9 o IE10 no son tan problemáticos como las versiones anteriores ¿Y si sólo quieres descartar del 8 para abajo? Bueno, toca cambiar un poco el código, para así poder detectar el número de versión (que por suerte está casi extinto, pero todavía arreglo equipos con Internet Explorer 6):

if(preg_match('/(?i)MSIE [5-8]/',$_SERVER['HTTP_USER_AGENT']))
{
   //Aquí lo que va a hacer si es menor que 8
}
else
{
    //Aquí el resto de navegadores y explorers más nuevos.
}

En fin, si queréis sí permitir el 8 y no el 6 y el 7… bueno, pues cambiáis el rango en la expresión regular del ejemplo, y listo.

El uso de la etiqueta meta viewport

En el mundo de la web móvil la etiqueta meta viewport se ha convertido en un elemento esencial, básico en los últimos tiempos. Inicialmente introducida por Apple en su navegador Safari para iPhone, rápidamente fue adoptada por otros navegadores hasta hacerse habitual en todos los OS móviles. Esta etiqueta busca dar una serie de directrices a los navegadores para que rendericen adecuadamente la web.

Hay que ponerse un poco en situación: cuando aparecieron los primeros smartphones no había webs adaptadas para dispositivos móviles, y pasó tiempo hasta que las hubo (a día de hoy todavía hay muchas páginas que no se visualizan correctamente). ¿Solución? Que el teléfono «emule» una pantalla más grande y la web original se redimensione a ese tamaño. La idea es buena ¿El problema? Bueno, que era una solución temporal para aquel momento, pero que en la actualidad se queda coja. Este sistema que nos muestra una pantalla reducida hace que si hemos hecho una maquetación responsiva con media queries la cosa no acabe de funcionar. Para eso está meta viewport, para establecer el ancho, el alto o el zoom de la página.

La meta viewport utiliza una serie de pares de claves=valores para definir diversos comportamientos del navegador a la hora de renderizar la web:

<meta name="viewport" content="
	width = [tamaño en pixels | device-width ],
	height = [tamaño en pixels | device-height],
	initial-scale = float mayor que 0.1,
	minimum-scale = float mayor que 0.1,
	maximum-scale = float mayor que 0.1,
	user-scalable = [yes | no]
">

<!--Un ejemplillo real tras la teoría-->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

Muy bien ¿y para qué vale cada una?:

Bueno, width lógicamente para definir el ancho de la pantalla. Podéis definir un ancho fijo, lo cual en términos generales viene a ser un epic fail. En cambio si usáis device-width esta ya se adaptará directamente al dispositivo.

Sobre heigth lo mismo, sólo que en este caso se define el alto. En la práctica no se me ocurre quién querría definir un alto estático, pero existir existe.

Para regular qué zoom tendrá por defecto la página está initial-scale, a la cual le tienes que dar un valor a partir de 0.1, siendo el valor 1 el equivalente a no tener zoom (es decir, menos de uno reduce y más de 1 amplía).

La pareja maximum-scale y minimum-scale nos permiten definir cual será el zoom máximo y el mínimo que pueda aplicar el usuario. Como arriba, 1 es igual a que se vea tal cual, sin zoom.

Finalmente user-scalable lo que nos permite es definir si queremos que el usario pueda hacer zoom o no. Lo mejor es dejarlo en yes, ya que no es buena idea poner limitaciones al user, y mucho menos en el caso del zoom, ya que podría tratarse de alguien con problemas de visión que necesite ampliar la página para poder leerla. Con el maximum y el minimum scale tres cuartos de lo mismo, piensa bien qué hace si vas a poner límites.

En fin, con esto ya tienes otro paso para mejorar tus diseños web adaptados a dispositivos móviles.

AngularJS: Introducción y Hello World

Llevo unos días trasteando con el framework de Javascript AngularJS, libre y mantenido por Google. En su momento no lo incluí en mi pequeña selección de frameworks a ir mirando, pero al final he acabado por dedicarme a trastear con él. De momento tampoco he avanzado mucho, que este mes estoy liado, pero en el futuro os iré comentando.

Comencemos por la primera pregunta ¿para qué vale AngularJs? En fin, la idea de este framework es dinamizar las páginas HTML estáticas vinculando elementos de ese HTML con un modelo de datos que hemos definido en Javascript (a mano, o desde un JSON), permitiendo la interactividad con el usuario. En este caso, aunque se usa un patrón MVC la potencia es que nos permite, mediante bindings {{}} , acceder a la funcionalidad o a los datos. Es cierto que el resultado final lo podemos conseguir de otras muchas formas, pero AngularJS nos ahorrará muchas líneas de código. Algunos lo comparan ya con lo que significó jQuery en su momento para el desarrollo en Javascript.

AngularJS Logotipo
AngularJS

Para descargaros Angular, que por cierto cada versión tiene un nombre más delirante que la anterior (al momento de escribir esto estamos en la Monochromatic Rainbow, pero mi favorita es Flatulent Propulsion), podéis hacerlo desde la página del proyecto. Y desde la documentación de esa misma página he sacado el código para el primer ejemplo: un Hello World!. Pero claro, como hablamos de un framework que dota de actividad a vuestro CSS será más bien un Hello ______ (loquesea).

Empezamos, como siempre, por el marcado:


    <html ng-app>
      <head>
<script class="hiddenSpellError" type="text/javascript">// <![CDATA[
src</span>="http://code.angularjs.org/angular-1.0.2.min.js">
// ]]></script>
<script class="hiddenSpellError" type="text/javascript">// <![CDATA[
src</span>="script.js">
// ]]></script>
 </head>
 <body>
 <div ng-controller="HelloCntl">
 Your name: <input type="text" value="World" />
 <hr/>
 Hello {{name}}!
 <div>
 </body>
 </html>

Bien, como puedes ver en la cabecera cargamos como un script la librería de AngularJS (está copiado de un ejemplo antiguo, así que revisa cual es la última versión en el momento en que lo hagas) y debajo cargamos otro script con lo que hayamos programado en Javascript. Puedes ver que al div le hemos asignado un atributo llamado ng-controller. La idea de esto es definir que ese div estará dentro del ámbito del controlador que le indicamos (recuerda, estamos trabajando en un modelo MVC). Luego verás que al input le hemos puesto también un atributo, en ese caso ng-model. Lo mismo, estamos vinculando ese atributo al ámbito del modelo de datos definido, o explicado de forma más simple: el texto que hay ahí será el modelo de datos y se llamará name. Finalmente ves que al lado de Hello hemos incluido {{name}}, esencialmente la idea es que ese elemento entre llaves está relacionado en el elemento del modelo con el mismo nombre (que a su vez está relacionado con el input) ¿qué va a ocurrir? Pues el llamado two-way-data-binding: modificarás el modelo desde la vista y justo al mismo tiempo verás como los datos de la vista se modifican.

Ahora vamos con la parte del javascript, donde definimos el controlador y el modelo:

    function HelloCntl($scope) {
       $scope.name = 'World';
    }

Como puedes ver aquí definimos la función HelloCntl, que fue la que vinculamos en el marcado al div. Abajo simplemente hacemos que, por defecto, el nombre que aparezca sea World (para formar el Hello World). Si bien, si lo modificamos veremos como este cambia.

Logo AngularJS

Finalmente vamos a hablar de otro de los fuertes de AngularJS: el testeo del código. Porque AngularJS nos permite escribir test para comprobar el correcto funcionamiento, sin tener que meternos en absurdas y largas pruebas con algún complemento del navegador para depurar javascript. El teste sería este:

    it('should change the binding when user enters text', function() {
        expect(binding('name')).toEqual('World');
        input('name').enter('angular');
        expect(binding('name')).toEqual('angular');
    });

Si queréis ver en acción todo el ejemplo antes de testearlo vosotros, en la página de Angular (de donde lo he copiado yo) podréis hacerlo. Además de ver otros, como un juego del tres en raya.

En fin, ya puedes hacerte una idea de la potencia de este AngularJS, más adelante espero escribir más sobre el tema. Yo lo veo como una potente herramienta, sobre todo para el desarrollo de Apps móviles con HTML5 y CSS.

También añadiré que la principal idea es usar AngularJS con Node.js en el lado del servidor, si bien podéis desde ese lado el lenguaje que prefiráis (Ruby, PHP, Python).