Millones de usuarios de Google en todo el mundo usan aplicaciones JavaScript intensivas, como Gmail, Google Docs y Google Maps. Al igual que los desarrolladores de todo el mundo, los Googlers (empleados de Google) queremos grandes aplicaciones web que sean más fáciles de crear, por lo que hemos construido unas cuantas herramientas para ayudarnos a desarrollar estas aplicaciones (y muchas otras). Estamos contentos de anunciar la publicación en código abierto de estas herramientas, y estamos orgullosos de ponerlos a disposición de la comunidad de desarrollo web.
El compilador de Closure
El compilador de Closure es un optimizador de JavaScript que compila aplicaciones web en código JavaScript compacto y de alto rendimiento. El compilador elimina el código muerto, a continuación, reescribe y minimiza lo que queda para que se ejecute rápido en los motores de JavaScript de los navegadores. El compilador también comprueba la sintaxis, las referencias a variables, y los tipos, y advierte sobre otros problemas comunes de JavaScript. Estos controles y optimizaciones ayudan a escribir aplicaciones más depuradas y fáciles de mantener. Puedes utilizar el compilador con el inspector de Closure, una extensión de Firebug que hace que la depuración del código ofuscado casi tan fácil como la depuración de código legible por humanos.
Los beneficios de usar el compilador son:
- Eficiencia. El compilador reduce el tamaño de los archivos JavaScript y al mismo tiempo los hace más eficientes, ayudando a que las aplicaciones carguen más rápido y necesiten menos ancho de banda.
- Comprobación de código. El compilador genera avisos sobre JavaScript ilega y sobre operaciones potencialmente peligrosas, ayudándote a producir JavaScript más depurado y fácil de mantener.
Debido a que los desarrolladores de JavaScript son un grupo diverso, hemos creado una serie de formas distintas de ejecutar el compilador de Clausure. Hemos publicado a fuente abierta una herramienta de línea de comandos. Hemos creado una aplicación web que acepta código para compilación a través de un cuadro de texto o de una API REST. También estamos ofreciendo una extensión de Firefox que puede utilizar con Page Speed para ver convenientemente los beneficios en rendimiento de las páginas web.
Para probar el compilador:
- Descarga el paquete del compilador de Closure.
Crea un directorio llamadoclosure-compiler
.
Descarga el compilador del archivo compiler.jar y guárdalo en el directorioclosure-compiler
.
- Crea un archivo JavaScript
Crea un archivo llamadohello.js
que contenga el siguiente código:
// Una función sencilla. function hello(longName) { alert('Hola, ' + longName); } hello('Nuevo usuario');
Guárdalo en el directorioclosure-compiler
.
- Compila el archivo JavaScript.
Ejecuta el siguiente comando desde el directorioclosure-compiler
:
java -jar compiler.jar --js hello.js --js_output_file hello-compiled.js
Este comando crea un nuevo archivo llamadohello-compiled.js
, que contiene el siguiente JavaScript:
function hello(a){alert("Hola, "+a)}hello("Nuevo usuario");
El compilador ha eliminado los comentarios, el espacio en blanco y un punto y coma innecesario. El compilador ha reemplazado el nombre de parámetrolongName
por el más cortoa
. Esto genera un archivo mucho más pequeño que el original.
Para confirmar que el código JavaScript compilado aún funciona, incluyehello-compiled.js
en un archivo HTML como este:
<html> <head> <script src="closure-library-read-only/closure/goog/base.js"></script> <script src="hello.js"></script> </head> <body onload="sayHi()"> </body> </html>
Ahora carga el HTML en el navegador y deberías ver una bienvenida amigable. Para aprender más visita este documento sobre compilación avanzada y con archivos externos.
El inspector de Closure
El compilador de Closure modifica el código JavaScript original y genera código más pequeño y más eficiente, pero más difícil de leer y depurar. El inspector ayuda ofreciendo un mapeo del código fuente que identifica las líneas del código original y el compilado. De esa forma es posible ver el código original en tu editor preferido indicado en la variable de entorno
$EDITOR
.Sigue estos pasos para habilitar el mapeo de código fuente al usar el inspector:
- Instala Firebug y el inspector.
- Compila tu código JavaScript con el compilador de Closure y añade el parámetro
--create_source_map
. Por ejemplo, si tu archivo JavaScript se llamaexample.js
, ejecuta este comando desde el directorioclosure-compiler
para crear un mapa de código fuente en el ficheroexample-map
:
$ java -jar compiler.jar --js example.js --create_source_map ./example-map --js_output_file example-compiled.js
- Para depurar tu código en Firebug, abre una página web en Firefox que incluya
example.js
. Abre una ventana de Firebug y carga el archivo JavaScript compiladoexample-compiled.js
en el panel izquierdo. Selecciona la pestaña Source Mapping del panel derecho y especifica la localización del archivo de mapa de código fuenteexample-map
introduciendo la URL o haciendo clic en Open Local File y seleccionándolo.
- Tras cargar el mapa de código fuente, puedes encontrar el código original de cualquier código en los fuentes compilados. Para hacer esto, pulsa el botón derecho del ratón sobre cualquier código compilado y selecciona Show Original Source, tal y como se muestra a continuación:
Si has indicado la variable de entorno$EDITOR
al editor de tu elección, el archivo original se abre en ese editor en la línea que corresponde a la que has hecho el click. Si no lo has indicado, verás el nombre de fichero y el número de línea mostrados en un pop-up, así:
Traza mejorada de pila
Firebug incluye una representación de la traza de pila que puedes ver pulsando Stack en la parte derecha de la ventana.El inspector de Closure mejora la representación de la traza de pila mediante:
- Mostrando los nombres de función originales si se ha cargado el mapa del código fuente.
- Mostrando el archivo que contiene cada función.
- Facilitando un botón Copy Stack de forma que se pueda copiar el texto de la traza de pila.
Integración de Tests Unitarios
El inspector de Closure soporta la integración con el Framework de test de Closure. Para habilitar esta característica, pulsa la flecha en el menú Script de Firebug y habilita Handle JSUnit Failures. Si una aserción falla en el Framework de testeo, el Inspector de Closure establece un punto de ruptura sobre la aserción y pausa la ejecución.Aquí hay un ejemplo de punto de ruptura sobre una aserción:
La Biblioteca de Closure
La biblioteca de Closure es una amplia colección de código JavaScript modular, bien probada y multi-navegador. Los desarrolladores Web pueden coger solamente lo que necesiten de un amplio conjunto de widgets reutilizables y controles de interfície de usuario, así como de utilidades de bajo nivel para el DOM, comunicación con el servidor, animación, estructuras de datos, pruebas unitarias, edición de texto rico, y mucho, mucho más. (De verdad. Echa un vistazo a la documentación.)
JavaScript carece de una biblioteca de clases estándar como STL o JDK. En Google, la biblioteca de Closure hace el papel de "nuestra biblioteca estándar de JavaScript" para la creación de grandes aplicaciones web complejas. Es intencionadamente agnóstica en cuanto a servidor y destinada para ser usada con el compilador de Closure. Puedes hacer un proyecto grande y complejo (con espacios de nombres y comprobación de tipos), y aún así, pequeño y rápido a través del cable (con compilación). La Biblioteca de Closure proporciona utilidades para tareas comunes de manera que pases el tiempo escribiendo la aplicación en lugar de escribir utilidades y abstracciones de navegador.
Si estás desarrollando una aplicación grande o creciente, podrías beneficiarte de la amplitud de la biblioteca. Una biblioteca bien probada puede aislarte de los problemas de compatibilidad entre navegadores y ahorrar tiempo de programación en el lado del cliente, permitiendo que te dediques a la parte divertida.
Empezando con la biblioteca de Closure
Este ejercicio de "Hola Mundo" te introduce en el proceso de usar la biblioteca en una página web. Para hacer este ejercicio necesitas estar familiarizado con JavaScript, y con un cliente de Subversion. Podrías tener ya uno. Lo sabrás intentando ejecutar el comando del paso 1. Hola Closure
Para empezar con la librería Closure, utiliza funciones JavaScript de Closure en una página web simple siguiendo estos pasos:Paso 1: Descargar la biblioteca
Descarga la biblioteca de Closure desde el repositorio de Subversion ejecutando siguiente comando desde consola: svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library-read-only
Podrías necesitar un cliente de Subversion para ejecutar el comando, aunque podrías tener ya uno. Prueba el comando, y si no funciona, descarga e instala un cliente de Subversion.
Tras ejecutar el comando deberías tener un directorio llamado
closure-library-read-only
que contenga el código de la librería. Paso 2: Crear un archivo JavaScript que use la biblioteca de Closure
Guarda el siguiente JavaScript en un archivo llamadohello.js
. Pon este archivo junto al directorio closure-library-read-only
. goog.require('goog.dom'); function sayHi() { var newDiv = goog.dom.createDom('h1', {'style': 'background-color:#EEE'}, 'Hola Mundo!'); goog.dom.appendChild(document.body, newDiv); }
Paso 3: Crea un archivo HTML
Guarda el siguiente HTML en un archivo llamadohello.html
. Pone este archivo junto al directorio closure-library-read-only
y el archivo hello.js
. <html> <head> <script src="></script> <script src="hello.js"></script> </head> <body onload="sayHi()"> </body> </html>
Paso 4: Dí Hola a la biblioteca
Abre el archivo HTML en el navegador. Deberías de ver las palabras "Hello world!":¿Cómo funciona el ejemplo?
El JavaScript dehello.js
usa dos funciones que no define: goog.dom.createDom()
y goog.dom.appendChild()
. ¿De dónde vienen esas funciones?Esas funciones están definidas en la biblioteca de Closure que descargaste en el paso 1, dentro del archivo
closure-library-read-only/dom/dom.js
. Para hacer uso de esas funciones, el ejemplo hace dos cosas:
- Incluye la orden
goog.require('goog.dom')
al principio del JavaScript del paso 2. - Incluye el archivo de arranque de la biblioteca
base.js
en el HTML del paso 3.
base.js
define la función goog.require()
. La llamada de función goog.require('goog.dom')
carga el archivo JavaScript que define las funciones del espacio de nombres goog.dom
, junto con otros archivos de la biblioteca de Closure que esas funciones necesitan.La biblioteca de Closure carga esos archivos agregando dinámicamente una etiqueta
script
al documento por cada archivo necesitado de la biblioteca. Así, por ejemplo, la orden goog.require('goog.dom')
hace que la siguiente etiqueta sea agregada al document, donde path-to-closure
es el camino desde el archivo HTML hasta el directorio que contiene base.js
: Normalmente una sola orden
goog.require()
cargará sólo una fracción de la base de código de la biblioteca. Incluir
base.js
no es la única forma de incluir el código de la librería, pero es la forma más fácil de empezar. En cualquier caso, no importa como cargues el código de la librería, siempre usarás goog.require()
para declarar las partes de la librería que necesitas. Construir una aplicación con la biblioteca de Closure
Este otro tutorial te introduce en la experiencia de usar la biblioteca dando un paseo por la construcción de una aplicación simple.Usa estos enlaces para descargar los dos archivos de código fuente usados en el tutorial:
Este tutorial explica las diferentes partes de estos archivos paso a paso. Fíjate que el archivo
notepad.html
no funcionará hasta que no descargues y enlaces tu copia de la biblioteca, tal y como se describe a continuación. La aplicación de Notas
Este tutorial ilustra el proceso de construir una simple aplicación para mostrar notas. El ejemplo: - crea un espacio de nombres para la aplicación,
- usa la función de la biblioteca
goog.dom.createDom()
para crear la estructura de Document Object Model (DOM) para la lista, y - usa una clase de la biblioteca en la lista de notas para permitir al usuario abrir y cerrar elementos de la lista.
Creando un espacio de nombres con goog.provide()
Cuando usas bibliotecas JavaScript de fuentes distintas, siempre existe la posibilidad de que algún archivo Javascript redefina una variable global o un nombre de función que ya uses en tu código. Para minimizar el riesgo de este tipo de colisión de nombres, usa la funcióngoog.provide()
de la librería para crear un espacio de nombres para tu código. Por ejemplo, la aplicación de Notas usa objetos
Note
creados por una función constructor Note()
. Si cualquier otro archivo JavaScript define una función global o una variable Note
, sobreescribiría al constructor. Por tanto, el ejemplo crea un espacio de nombres para este constructor con la siguiente llamada a goog.provide
: goog.provide('tutorial.notepad.Note');
La función
goog.provide()
se asegura de la existencia de la estructura de objeto JavaScript indicada por su argumento. Comprueba si existe cada propiedad de objeto en la ruta de la expresión y si no existe la inicializa. La función anterior es equivalente a: tutorial = tutorial || {}; tutorial.notepad = tutorial.notepad || {}; tutorial.notepad.Note = tutorial.notepad.Note || {};
Puesto que
goog.provide()
sólo inicializa propiedades si no existen previamente, nunca sobreescribirá una propiedad.Fíjate que las órdenes
goog.provide()
tiene la ventaja añadida de que el script de resolución de dependencias calcdeps.py
puede usarlas. Echa un vistazo a Usar el script de cálculo de dependencias para aprender cómo usar calcdeps.py
Una vez que la estructura de objeto
tutorial.notepad.Note
exista, el ejemplo asigna la función constructor a la propiedad Note
. tutorial.notepad.Note = function(title, content, noteContainer) { this.title = title; this.content = content; this.parent = noteContainer; };
El constructor
Note
está ahora en el espacio de nombre tutorial.notepad
creado con goog.provide()
. Creando una estructura DOM con goog.dom.createDom()
Para mostrar unaNote
en el documento HTML, el ejemplo facilita a la clase Note
el siguiente método: tutorial.notepad.Note.prototype.makeNoteDom = function() { // Crea la estructura DOM que representa la nota. this.headerElement = goog.dom.createDom('div', {'style': 'background-color:#EEE'}, this.title); this.contentElement = goog.dom.createDom('div', null, this.content); var newNote = goog.dom.createDom('div', null, this.headerElement, this.contentElement); // Agrega la estructura DOM de la nota al documento. goog.dom.appendChild(this.parent, newNote); };
Este método usa la función de la biblioteca
goog.dom.createDom()
. La siguiente orden goog.require()
incluye el código para esta función: goog.require('goog.dom');
Para incluir una función como
goog.dom.createDom()
que no sea un constructor, pasa el espacio de nombres que contenga la función a goog.require
(en este caso solamente goog.dom
). No necesitas incluir el nombre de la función en la orden goog.require()
a menos que requieras de una clase. Usando una clase de la biblioteca ilustra una órden goog.require()
para este caso. La función
goog.dom.createDom()
crea un nuevo elemento DOM. Por ejemplo, la siguiente órden de makeNoteDom()
crea un nuevo elemento div
. this.headerElement = goog.dom.createDom('div', {'style': 'background-color:#EEE'}, this.title);
El segundo argumento en esta llamada a
createDom()
especifica los atributos a agregar al elemento, y el tercer argumento especifica un hijo que añadir al elemento (una cadena en este caso). Ambos, el segundo y el tercer parámetro, son opcionales. Mira la referencia de la API para más información sobre createDom()
. El método
makeNoteDom()
simplemente crea un argumento de una sola Note. Para crear una lista de notas, el ejemplo incluye una función makeNotes()
que toma un array de de datos de notas e instancia un objeto Note
por cada uno, llamando al método makeNoteDom()
de Note
. tutorial.notepad.makeNotes = function(data, noteContainer) { var notes = []; for (var i = 0; i < data.length; i++) { var note = new tutorial.notepad.Note(data[i].title, data[i].content, noteContainer); notes.push(note); note.makeNoteDom(); } return notes; };
Usando una clase de la biblioteca
Con sólo dos líneas de código, el ejemplo hace de cada nota unZippy
. Un Zippy
es un elemento que puede ser plegado y desplegado para ocultar o mostrar contenido. Primero el ejemplo agrega una nueva orden require()
para la clase Zippy
: goog.require('goog.ui.Zippy');Entonces añade una línea al final del método
makeNoteDom
: tutorial.notepad.Note.prototype.makeNoteDom = function() { // Crea la estructura DOM para representar la nota. this.headerElement = goog.dom.createDom('div', {'style': 'background-color:#EEE'}, this.title); this.contentElement = goog.dom.createDom('div', null, this.content); var newNote = goog.dom.createDom('div', null, this.headerElement, this.contentElement); // Agrega la estructura DOM de la nota al documento. goog.dom.appendChild(this.parent, newNote); // NUEVA LINEA: return new goog.ui.Zippy(this.headerElement, this.contentElement); };La llamada al constructor
new goog.ui.Zippy(this.headerElement, this.contentElement)
asigna un comportamiento al elemento nota que conmutará la visibilidad de contentElement
cuando el usuario haga clic sobre headerElement
. Para más información sobre la clase Zippy, echa un vistazo a la documentación de la API de Zippy. Usando el Notepad en un documento HTML
A continuación se puede ver el código JavaScript completo para esta aplicación de ejemplo:goog.provide('tutorial.notepad'); goog.provide('tutorial.notepad.Note'); goog.require('goog.dom'); goog.require('goog.ui.Zippy'); /** * Itera sobre una lista de objetos de datos de nota, crea una instancia de Nota * para cada uno, y le dice a la instancia que construya su estructura DOM. */ tutorial.notepad.makeNotes = function(data, noteContainer) { var notes = []; for (var i = 0; i < data.length; i++) { var note = new tutorial.notepad.Note(data[i].title, data[i].content, noteContainer); notes.push(note); note.makeNoteDom(); } return notes; }; /** * Gestiona los datos e interfície de un solo nodo */ tutorial.notepad.Note = function(title, content, noteContainer) { this.title = title; this.content = content; this.parent = noteContainer; }; /** * Crea la estructura DOM para la nota y la agrega al documento. */ tutorial.notepad.Note.prototype.makeNoteDom = function() { // Create DOM structure to represent the note. this.headerElement = goog.dom.createDom('div', {'style': 'background-color:#EEE'}, this.title); this.contentElement = goog.dom.createDom('div', null, this.content); var newNote = goog.dom.createDom('div', null, this.headerElement, this.contentElement); // Agrega la estructura DOM de la nota al documento goog.dom.appendChild(this.parent, newNote); return new goog.ui.Zippy(this.headerElement, this.contentElement); };Puedes tener este código descargando el archivo notepad.js. El siguiente HTML usa este código de bloc de notas para mostrar una lista de notas en una página web:
<html> <head> <title>Notepad</title> <script src="closure-library/base.js"></script> <script src="notepad.js"></script> </head> <body> <div id="notes"> </div> <script> function main() { var noteData = [ {'title': 'Note 1', 'content': 'Content of Note 1'}, {'title': 'Note 2', 'content': 'Content of Note 2'}]; var noteListElement = document.getElementById('notes'); var notes = tutorial.notepad.makeNotes(noteData, noteListElement); } main(); </script> </body> </html>Puedes tener esta página descargando el archivo notepad.html, Esta página:
- incluye una etiqueta
script
para el archivobase.js
de la biblioteca. El atributosrc
de esta etiqueta es el camino desde el archivo HTML hasta el archivobase.js
de la biblioteca. - incluye una etiqueta
script
para el archivo que contiene el código para el bloc de notas. - incluye un script en la página que inicializa la lista de notas con una llamada a
makeNotes()
. La funciónmakeNotes()
toma dos argumentos: un array de Objetos, cada uno conteniendo los datos de una nota, y el elemento DOM bajo el que construir la estructura DOM de la lista de notas
Plantillas de Closure
Las plantillas de Closure surgieron de un deseo de tener plantillas web que estén precompiladas para ser ejecutadas de forma eficiente por JavaScript. Las plantillas de Closure tienen una sintaxis simple y natural para programadores. A diferencia de los tradicionales sistemas de plantillas, puedes pensar en las plantillas de Closure como pequeños componentes que se unen para formar una interfície de usuario, en lugar de tener que crear una gran plantilla por cada página. Las plantillas de Closure se aplican para JavaScript y para Java, así que puedes usar las mismas plantillas en el servidor y en el cliente. El compilador, la biblioteca, las plantillas y el inspector de Closure se iniciaron como proyectos de 20% del tiempo de Googlers y cientos de ellos han contribuido con miles de parches. Hoy en día, cada herramienta de Closure se ha convertido en una parte clave de la infraestructura de JavaScript detrás de las aplicaciones web en Google. Por eso estamos particularmente entusiasmados de abrir su código para fomentar y apoyar el desarrollo web fuera de Google. Queremos saber lo que piensas, pero más importante aún, queremos ver que podéis hacer con ellas. Así que bájatelo y diviértete!Addendum: Parece que Andrea Giammarchi no está muy de acuerdo con las ventajas ofrecidas por el nuevo proyecto de Google. Ha encontrado fácilmente un ejemplo en el que el compilador hace que el código deje de funcionar (aunque hay que decir que hace mal uso de las variables globales que un buen estilo de programación debería evitar). Por otro lado analiza el código de la librería y encuentra distintos problemas de rendimiento que una librería orientada a la velocidad no debería tener. Quizás tenga razón y todo se deba a que detrás de esas herramientas hay programadores expertos en Java y no en JavaScript...
No hay comentarios:
Publicar un comentario