Search code examples
symfonycachingtwiggulpassetic

Gulp/Symfony2: How can I avoid overwriting my js/css imports when cache busting?


I have a gulp build process for my Symfony2 application and am trying to integrate cache busting, but have hit a roadblock. I use gulp-rev to append a hash to my concatenated javascript file and output a manifest file to map between the original and the hashed filename. I currently have a twig template that has a single script tag to import all my correctly built javascript files, but I need to find a way of updating that script tag to point at the version of the file with the correct hash, ensuring that a fresh version of the file is downloaded every time the hash changes.

I have thought of a number of solutions which I've described below, but none of them feel right. Does anyone have a better/correct solution, or some reasoning as to why I should go with one of the ways I have already thought of.

  • Use gulp-revreplace to replace the reference to app.js in my_template.html.twig to be a reference to app-8de7016eef.js as defined by the mapping in the manifest file. Problem: This will overwrite my actual template file if the command in run in my dev environment, leaving me with a dirty git tree and changes that shouldn't be committed.
  • Have gulp output an assets template file which is stored in public/html which is not committed to version control, and includes the correct script tag based on whether it was run on prod/dev environment (i.e. <script src='js/app.js'> on dev, and <script src='js/app-8de7016eef.js'> on prod. My main template can then @include 'public/html/assets.html.twig' and never needs to be overwritten. Problem: This gets increasingly complex when there are multiple templates that extend each other, and when there is both CSS and JS in separate blocks that need to be overwritten by other templates. It also feels messy to generate and output a twig file from my gulp task.
  • Use assetic to manage cache busting: instead of using gulp-rev I could use the {% javascripts 'public/js/app.js' %} <script src="{{ asset_url }}"></script> {% endjavascripts %} syntax of assetic and let that handle the cache busting for me. Problem: The whole point of using gulp was to move away from assetic, and if I have to use both gulp and assetic then the complexity is increased.

So has anyone solved the cache-busting with gulp and symfony problem? How did you do it?


Solution

  • You should make use of the two config directives:

    framework.templating.assets_version
    framework.templating.assets_version_format
    

    You can read more about them in the documentation of the FrameworkBundle.

    They do work with the regular {{ asset() }} function and don't require AsseticBundle.

    Then just dump a parameter/config-file that assigns i.e. the md5sum of your compressed frontend source-files folder to assets_version in a git pre-commit hook.

    .git/hooks/pre-commit

    #!/usr/bin/env sh
    
    echo "framework.templating.assets_version: $(tar -cf - ./src/Frontend | md5sum)" \
    > app/config/assets_version.yml
    

    app/config/config.yml

    # ...
    imports:
      # ...
      - { resource: './assets_version.yml' }