Pages

Friday, September 30, 2016

Inmadusa.com [Part 8]: Add cache invalidation with gulp-cache-buster

Up to now we have a setup that compiles the view templates on save and drops a new 'templates.js' file that is then loaded by the main page in the browser. The file will be cached by the browser so that the site will load faster on subsequent visits, however, we need a way to notify the browser that it needs to re-request the file when we have made changes to it.

Enter gulp-cache-buster. This is handy package that works in conjunction with gulp-hasher to replace URLs of these type of resources and replaces them with a hash so that the browser's cache can be invalidated when the content changes.

The setup takes some work. First, whenever a file is generated you need to add it to the dictionary of hashes using gulp-hasher. Below is an example of a task that concatenates all the .css files into a single file, notice how at the end there is a call to 'hasher()' to add the file to the dictionary of hashes.
var hasher = require('gulp-hasher');

gulp.task('css', function() {
    return gulp.src('css/*.css')
    .pipe(concat('index.css'))
    .pipe(gulp.dest('./'))
    .pipe(hasher());
});

After you have done all of this you can use the dictionary of hashes to generate urls where they are needed. This is done by using a special 'ASSET' syntax as can be seen in the main .html file:
<html>
    <head>
        <title>Inmadusa</title>
       
        <link rel="stylesheet" href="ASSET{index.css}">
    </head>
<body>

    <div class="main"></div>
    ...
    <script src="ASSET{js/templates.js}"></script>
    <script src="ASSET{js/resources.js}"></script>
    <script src="ASSET{js/index.js}"></script>
</body>
</html>

The last step is to write a gulp task that takes the .html file and rewrites the 'ASSET' markers with hashed urls:
var buster = require('gulp-cache-buster');

gulp.task('html', ['js', 'css'], function() {
    return gulp.src('index-src.html')
    .pipe(buster({
        assetRoot: __dirname,
        assetUrl: '/',
        env: 'production',
        hashes: hasher.hashes
    }))
    .pipe(rename('index.html'))
    .pipe(gulp.dest('./'));
});

As can be seen the 'buster' function is the one responsible for making the replacements and it takes in the dictionary that was built during all the generator tasks. The final file will be renamed to 'index.html' and placed at the root of the site and it looks something like this (notice the query strings at the end of each url):
<html>
    <head>
        <title>Inmadusa</title>
       
        <link rel="stylesheet" href="/index.css?v=13578967">
    </head>
    <body>

    <div class="main"></div>
    ...
    <script src="/js/templates.js?v=87844975"></script>
    <script src="/js/resources.js?v=d8c45e9c"></script>
    <script src="/js/index.js?v=ec0b1667"></script>
</body>
</html>

Perfect, the browser is now free to cache the script and css files and they will only be invalidated when the files change. Even though it is possible to do something similar with image resources I chose not to do it for this site.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.