Versionando los assets en Symfony 2

Actualmente en el proyecto donde estoy trabajando, me surgió la necesidad de añadir a los assets un parametro de versionado, para que tanto la cache de Symfony como la del navegador(cliente) dejaran de cachear dichos archivos y obtuvieran los nuevos. No se si sera la mejor forma o si existen alternativas mejores(seguro que sí, pero yo no las he encontrado).

Así que os pongo mi solución, después de buscar y juntar algunas ideas de varios sitios, entre ellos este:

http://developer.happyr.com/rename-dump-from-asseticbundle

Symfony no dispone de ninguna configuración que permita hacerlo de forma automatizada en cada deploy, sino que te dicen que lo modifiques tu manualmente en el config.yml. El mayor problema es que al hacer un assetic: dump si los assets ya estan generados, no se les cambia el nombre, y por tanto aunque el contenido cambie, el nombre es el mismo y de eso no se entera la cache. Desde la documentación oficial te dicen que puedes configurarlo así (http://symfony.com/doc/current/reference/configuration/framework.html#ref-framework-assets-version):

– config.yml:

framework:
    # ...
    templating: 
        engines: ['twig']
        assets_version: 2.1.5.3
        assets_version_format: %%s?v=%%s

Esto lo que hace es que los assets se enlacen en las plantillas twig de la siguiente forma:  /images/logo.png?v=2.1.5.3

El inconveniente de esto es que en cada deploy tenemos que acordarnos de venir aquí y modificar esa version a mano. Se me ocurrió que esto se podia automatizar de alguna forma, y que ese código de versión nuevo que iba a usar en cada deploy iba a ser el hash del ultimo commit de Git.

Así que vamos al lio:

1- Creamos un nuevo fichero de configuración de un nuevo parámetro llamado version.yml y metemos  un nuevo parámetro llamado “git_commit”

-version.yml

parameters:
    git_commit: 123

2- Añadimos en los imports el nuevo archivo y añadimos la configuración de los assets.

-config.yml:

imports:
    - { resource: version.yml }
framework:
    # ...
    templating: 
        ...
        assets_version: %git_commit%
        assets_version_format: %%s?v=%%s

3- Creamos un fichero shell-script para ejecutarlo en cada deploy y que se encargue de coger el ultimo commit de git y meterlo en el fichero donde hemos declarado el nuevo parámetro con la versión. En mi proyecto

-generate_version_assets.sh

#!/bin/bash

# This script gets the last commit of git to be used in assets version
# Source: http://developer.happyr.com/rename-dump-from-asseticbundle

FILE="./app/config/version.yml"

echo "#This is an auto generated file that will be updated at every deploy" > $FILE
echo "parameters:" >> $FILE
echo "    git_commit: '$(git rev-parse --short HEAD)'" >> $FILE

De esta forma, en cada deploy y después de generar los assets mediante los comandos (assets: install y assetic: dump), deberemos ejecutar este script para que se guarde correctamente el numero de version correspondiente y de esa forma no se cachee ni por Symfony ni por el navegador del usuario. En mi proyecto dispongo de otro script que genera estos assets y ademas, crea el numero de version nuevo de forma automática.

Si examinamos el código de la web veremos que ahora se añade en cada asset un nuevo parámetro tal que así :

/js/2e4fdaa.js?v=a33d45

Espero que os haya sido util y si tenéis cualquier duda o comentario al respecto no tenéis mas que comentarlo.

Un fuerte abrazo y hasta el proximo truco ¡

Anuncios

2 comentarios en “Versionando los assets en Symfony 2

  1. En mi caso, uso como parámetro el número de versión que sale de composer.json.

    A grandes rasgos sería:
    namespace Acme\AcmeBundle\DependencyInjection;

    use Symfony\Component\Config\Definition\Builder\TreeBuilder;
    use Symfony\Component\Config\Definition\ConfigurationInterface;

    class Configuration implements ConfigurationInterface
    {
    public function getConfigTreeBuilder()
    {
    $treeBuilder = new TreeBuilder();
    $rootNode = $treeBuilder->root(‘acme_bundle’);

    $rootNode
    ->children()
    ->scalarNode(‘version’)
    ->end()
    ->end()
    ;

    return $treeBuilder;
    }
    }
    —————————-
    namespace Acme\AcmeBundle\DependencyInjection;

    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\Config\FileLocator;
    use Symfony\Component\HttpKernel\DependencyInjection\Extension;
    use Symfony\Component\DependencyInjection\Loader;
    use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;

    class AcmeExtension extends Extension implements PrependExtensionInterface
    {
    public function load(array $configs, ContainerBuilder $container)
    {
    $configuration = new Configuration();
    $config = $this->processConfiguration($configuration, $configs);
    $container->setParameter(‘acme.version’, $config[‘version’]);

    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.’/../Resources/config’));
    $loader->load(‘services.yml’);
    }

    public function prepend(ContainerBuilder $container)
    {
    try {
    $array = json_decode(file_get_contents(__DIR__.’/../../../../composer.json’), true);
    $version = $array[‘version’];
    } catch (\Exception $ex) {
    $version = ”;
    }

    $container->prependExtensionConfig(‘framework’, array(‘assets’ => array(‘version’ => $version)));
    $container->prependExtensionConfig($this->getAlias(), array(‘version’ => $version));
    }
    }

    Me gusta

  2. Hola amigo y gracias por tu interes. Podria ser otra opcion, siempre y cuando en tu composer.json tuvieras la key “version” definida y en cada deploy actualizaras o instalaras los venndors para que esa version cambie, cierto? Bueno, si en cada deploy lo haces, no me parece mala solución, pero de esta forma obligas a quien use esto a instalar los vendors. Gracias por tu aporte.

    Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s