Merging y compresión de Javascripts al vuelo con Django
Después de algunos parches enviados a Django, y con muchos desarrollos que por falta de tiempo no he podido liberar (ya que la liberación de código no es tarea trivial), hoy estoy muy orgulloso de haber subido mi primera receta de código a djangosnippets, la cual creo que resultará muy útil a cualquiera.
Os comento en que consiste, pero antes dejadme comentar el cómo surge la idea. Uno de los proyectos que llevo adelante trata de la creación de una herramienta de trabajo colaborativo, realizado en Django, el cual estoy convencido de que es, con creces, el sistema de desarrollo web más productivo y a la vez perfeccionista que existe. Pues bien, estaba en ese momento haciendo una optimización de rendimiento del sistema, cuando ví que una de mejoras más considerables sería reduciendo el número de peticiones HTTP creando una utilidad que mezclara todos los ficheros Javascripts en uno y además lo comprimiera (compresión no binaria, sino de texto, eliminando espacios, comentarios, etc.). Esto reduciría bastante el tiempo de carga, sobre todo teniendo en cuenta que suelen existir muchos ficheros Javascript distintos en una misma página, sobre todo ahora, que está tan de moda el tema AJAX y demás.
Así, esta mañana me puse a implementarlo, y en un tiempo record de tres horas efectivas (interrumpidas en el tiempo, eso sí) conseguí terminarlo, gracias eso sí en parte a la maravilla de desarrollar con software libre, que en este caso me permitió reaprovechar parte del algoritmo de compresión de Javascripts que ya tenía implementado Plone en su producto ResourceRegistries.
Todo esto acabó siendo la receta previamente mencionada, que en concreto consiste en extender el sistema de plantillas de Django con una nueva etiqueta (templatetag en jerga Djanguera), que te permite, introducir el siguiente fragmento entre el código HTML de cualquier plantilla:
...
<head>
{% jsmerge salidamezclada fichero1.js fichero2.js fichero3.js fichero4.js %}
</head>
...
La etiqueta jsmerge, que es la que implementé en la receta, se encargará de:
- Localizar los ficheros javascripts fichero1.js, fichero2.js, fichero3.js, fichero4.js
- Leer y comprimir su contenido
- Concatenar los contenidos en un fichero llamado salidamezclada.js
Al final, lo que la etiqueta devuelve es el fragmento HTML de inclusión del fichero javascript mezclado y comprimido. El ejemplo anterior devolvería lo siguiente:
<head>
<script type="text/javascript" src="salidamezclada.js"></script>
</head>
Salida mezclada sería un fichero que concatena los otros cuatro comprimidos. Para que veáis el resultado de la compresión, os pongo un fragmento del fichero prototype.js, de la libreria Prototype, la tantas veces usada en sitios web que usan AJAX:
/* Prototype JavaScript framework, version 1.5.1_rc4
* (c) 2005-2007 Sam Stephenson
*
* Prototype is freely distributable under the terms of an MIT-style license.
* For details, see the Prototype web site: http://www.prototypejs.org/
*
/*--------------------------------------------------------------------------*/
var Prototype = {
Version: '1.5.1_rc4',
Browser: {
IE: !!(window.attachEvent && !window.opera),
Opera: !!window.opera,
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1
},
BrowserFeatures: {
XPath: !!document.evaluate,
ElementExtensions: !!window.HTMLElement,
SpecificElementExtensions:
(document.createElement('div').__proto__ !==
document.createElement('form').__proto__)
},
...
Ahora el mismo fragmento de fichero después de la compresión:
var Prototype={
Version: '1.5.1_rc4',
Browser:{
IE:!!(window.attachEvent&&!window.opera),
Opera:!!window.opera,
WebKit: navigator.userAgent.indexOf('AppleWebKit/')>-1,
Gecko: navigator.userAgent.indexOf('Gecko')>-1&& navigator.userAgent.indexOf('KHTML')==-1},
BrowserFeatures:{
XPath:!!document.evaluate,
ElementExtensions:!!window.HTMLElement,
SpecificElementExtensions:(document.createElement('div').__proto__!==
document.createElement('form').__proto__)},
Aún se podría comprimir más y quitar los saltos de línea, pero ya deja de ser una compresión tan segura y puede dar fallas de código, así como dificultar la depuración mediante firebug.