Ya hablamos de servir archivos estáticos de una forma óptima. Este post puede leerse como una continuación del artículo “Automatically Version Your CSS and JavaScript Files” de Particletree, refinando la solución que proponen ahí.
Un breve resumen de ese artículo (léetelo!): A la hora de servir los archivos estáticos como .js o .css, la idea es que el cliente los cachée durante un periodo muy largo de tiempo (por ej. 10 años) y no tenga que andar descargándolos a cada petición de página que se realice. Pero si modificamos alguno de estos archivos, necesitamos una forma de “forzar” que el cliente se vuelva a descargar ese archivo modificado. Para esto introducimos la “versión” del archivo, en el nombre del mismo, ya sea en el propio nombre mediante mod_rewrite (o similar), ya sea en la querystring como parámetro. Al cambiar la versión del archivo, el browser lo descargaría de nuevo que es lo que nos interesa.
Todo esto está muy bien explicado en el comentado artículo.
Versionando
Ahora el tema viene por cómo fijar esa “versión” de cada archivo estático. La idea obviamente es no tener que hacerlo a mano, y por eso en el artículo de Particletree lo hacen mediante filemtime(), para sacar el timestamp de la última modificación del archivo en cuestión.
Aunque es un primer enfoque, a mí personalmente no me gusta mucho esa opción. Implicaría un costoso acceso a disco con cada petición que se solicite, y aunque se podría evitar este acceso innecesario mediante un script que almacene los timestamps en un include… ya puestos… ¿por qué no hacerlo con la versión del archivo dentro del repositorio?
El script: staticVersions.py
Aquí es donde viene mi aportación. Es un script Python que escanea los directorios que le pases como argumentos y devuelve un array PHP con el nombre de los archivos y su correspondiente versión en el repositorio (esto es, la última revisión en la que cambiaron).
Descarga el script aquí.
Ejemplo:
./staticVersions.py -d ./js -d ./css
<?php
//$productionSite - if set and true, append versions to static files in template ‘top.tpl’
$productionSite = true;
//array with filenames (as used in template ‘top.tpl’) and file SVN last revision
$staticFilesVersions = array(
‘/js/register.js’ => ‘1′ ,
‘/js/post.js’ => ‘15′ ,
‘/js/interface.js’ => ‘25′ ,
‘/js/visualizeus.js’ => ‘73′ ,
‘/css/general.css’ => ‘1′ ,
‘/css/ie.css’ => ‘38′ ,
‘/css/user.css’ => ‘1′ ,
‘/css/visualizeus.css’ => ‘1′ ,
‘/css/default.css’ => ‘52′ ,
‘/css/post.css’ => ‘15′
);
?>
De forma que cada vez que hagamos un svn update, se llame a staticVersions.py y se actualice el include correspondiente. En mi caso lo hago con un sencillo shell script, porque no tenía muy claro si con el hook post-commit se podría montar algo. Si a alguno le da por investigarlo, soy todo oídos!
Cabe mencionar que las keys del array que defino encajan con mi estructura de archivos tal y como los uso en las plantillas y tal y como lo sirve el webserver. Si vas a usar el script, posiblemente tengas que adecuar esto a tu propia estructura.
Encajando todo esto con tus plantillas
Cómo ya comenté en su día, yo uso plantillas nativas en PHP, nada de Smarty ni similares, así que: ¿cómo encajar todo esto en tus templates?
Como ya habéis visto, me defino una variable global que indica si el sitio está en producción o en desarrollo, y en función de eso reescribo los nombres de cada archivo estático bien con su versión en el repositorio o bien con su ultimo timestamp de modificación. De eso se encarga la siguiente función:
function autoVersion($url) {
if (isset($GLOBALS['productionSite']) && $GLOBALS['productionSite']) {
if (array_key_exists($url, $GLOBALS['staticFilesVersions']))
$version = $GLOBALS['staticFilesVersions'][$url];
else $version = ‘1′;
} else {
$stat = stat($_SERVER['DOCUMENT_ROOT'] . $url);
$version = $stat['mtime'];
}
return preg_replace(’!\.([a-z]+?)$!’, ".v$version.\$1", $url);
}
Y poco más, modificas en tu plantilla top (o similar) para que la parte de carga de archivos estáticos use la función autoVersion y estableces en mod_rewrite las correspondientes reglas para que Apache no se vuelva loco buscando archivos que no existen (ver artículo de Particletree) y listo!
Nota: Comentarios cerrados por spam. Si quieres añadir o corregir algo, usa el formulario de contacto.
Compártelo