If you aren’t using Grunt, you should start. It’s billed as “The Javascript Task Runner,” and it lives up to that in every way. You can automate almost anything. Last week, I wrote about using cache to speed up your site. Today, we’ll use Grunt to help bust that cache when we want to change a css file.

.htaccess

<IfModule mod_rewrite.c>
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
</IfModule>

Ok, this may look like garbledegook (technical term) to you, so I’ll explain what I can.

First off, I took this straight from the HTML5 Boilerplate htaccess file. I highly recommend you check it out. There are some apache config gems in there.

What you are looking at is a rewrite rule to reroute all requests made to the above filetypes, when they have certain naming conventions. We’ll be renaming our files when we edit them with a unique number, so that’s what we’ll look for. For example, any request to style.1234567.css will reroute to style.css. By updating this number, we can force the browser to bust the cache setup on the file, and reset the time to live. So if cache on style.css is set to 365 days, and we update it after 20 days, it will again reset to 365 with the new updates. Now that we are busting cache, let’s use grunt to rename these files before we deploy.

Grunt Replace Setup

For the next step, I’m going to assume you have a working knowledge of Grunt setup. If not, read up on it here. I’ll wait.

In order to replace our css filename with a variable, I’ll be using the grunt-replace plugin. Cd to the root of your project (where you hopefully installed Grunt) and run the following:

npm install grunt-replace --save-dev

This will not only install the plugin, but will save it into your package.json file. This will let you update the plugin in the future via running npm install. Now that we’re setup, on to the…

Gruntfile

module.exports = function(grunt) {
 
  // Project configuration.
  grunt.initConfig({
    
    // Replace object
    replace: {
      build_replace: {
        options: {
          variables: {
            // Generate a truly random number by concatenating the current date with a random number
            // The variable name corresponds with the same in our HTML file
            'hash': '<%= ((new Date()).valueOf().toString()) + (Math.floor((Math.random()*1000000)+1).toString()) %>'
          }
        },
        // Source and destination files
        files: [
          {
            src: ['public/index.html'],
            dest: 'public/build/index.html'
          }
        ]
      }
    }
 
  });
  
  grunt.loadNpmTasks('grunt-replace');
 
  // Default task, you can obviously name this whatever you like
  grunt.registerTask('default', ['replace']);
 
};

To change our css names, we’ll first setup a unique number variable called hash to add to them. It’s important this number be totally unique, because if you reuse an old number that is cached, your browser may reference the cached file rather than your update:

'hash': '<%= ((new Date()).valueOf().toString()) + (Math.floor((Math.random()*1000000)+1).toString()) %>'

Then, we’ll setup a source and destination file. This will tell grunt-replace what file to look for the hash variable in our source file, and kick out a destination file. This is the file that will be pushed live, replaced with our random number.

Below is the code for our source file. The hash var is prepended with @@, and is what will be replaced with what we setup in our gruntfile.

HTML

<html>
  <head>
    <script src="build/index.@@hash.js"></script>
  </head>
  <body>
  </body>
</html>

For this exercise, the replace task is setup as the default. This means that you can just run grunt on the command line, and it should be good to go. There are an infinite array of configurations you can add the replace task to. For my portfolio site, I’ve got grunt-replace wrapped into a build command I run, which also handles minification and uglification of assets.

Anywho, that’s a quick rundown of how you can use Grunt to bust cache. If you have another way of doing it, let me know! I’d love to hear it.

References