Introduction to Gulp.js 13: Revisioning

Introduction to Gulp.js 13: Revisioning

This is the 13th part of my series, Introduction to Gulp.js. Today I will write the task to revise my static assets.

Copy Vector Fonts for Production

Before I can work on the fun part of revisioning my asset files, I first have to write another boring and short task, which is doing one simple thing: Copying the fonts to the production assets folder.

gulp/config.js

copyfonts: {
  development: {
    ...
  },
  production: {
    src:  developmentAssets + '/fonts/*',
    dest: productionAssets + '/fonts'
  }
}

gulp/tasks/production/copy-fonts.js

var gulp = require("gulp");
var config = require("../../config").copyfonts.production;

/**
 * Copy fonts to folder
 */
gulp.task("copy:fonts:production", function () {
  return gulp.src(config.src).pipe(gulp.dest(config.dest));
});

Revisioning

Optimizing my assets is done. But one important thing is missing: Revisioning.

For better performance, one should always cache the assets for a long time. Hard drives are huge these days, but the speed for requesting assets isn’t that wonderful (on mobile devices). But one problem occurs if you cache the assets on a hard drive of a visitor. If you update a file, the browser will serve the old file. And if you cache it for 10 years, the user will never get the new asset, unless s/he deletes the browser cache manually. Yet what user does this?

That’s why we need to rename every file that has been changed to invalidate the cache. I remember the days when we had to add a number manually to our assets, like image_r1.png, or image_r2.png. This sucks. Today, reading the content of a file and generating a checksum can achieve this easier. This checksum will always be the same unless something gets changed.

My next task will rename all assets. This way, the application.css will become application-f084d03b.css. If I change one tiny thing in this file, it will get a new filename.

I install gulp-rev, which will handle this renaming of assets:

$ npm install --save-dev gulp-rev@2.0.1

gulp/config.js

revision: {
  src: {
    assets: [
      productionAssets + '/css/*.css',
      productionAssets + '/js/*.js',
      productionAssets + '/images/**/*'
    ],
    base: production
  },
  dest: {
    assets: production,
    manifest: {
      name: 'manifest.json',
      path: productionAssets
    }
  }
}

This task will rename all assets and create a JSON file containing all files, which were renamed and their old and new file names.

gulp/tasks/production/revision.js

var gulp = require("gulp");
var rev = require("gulp-rev");
var config = require("../../config").revision;

/**
 * Revision of all asset files and
 * write a manifest file
 */
gulp.task("revision", function () {
  return gulp
    .src(config.src.assets, { base: config.src.base })
    .pipe(gulp.dest(config.dest.assets))
    .pipe(rev())
    .pipe(gulp.dest(config.dest.assets))
    .pipe(rev.manifest({ path: config.dest.manifest.name }))
    .pipe(gulp.dest(config.dest.manifest.path));
});

Replacing Paths to Assets

The last step of my production build is to replace all occurrences of assets with a revised file name in all files.

This task will need gulp-rev-collector to replace the paths names to assets:

$ npm install --save-dev gulp-rev-collector@0.1.1

gulp/config.js

collect: {
  src: [
    productionAssets + '/manifest.json',
    production + '/**/*.{html,xml,txt,json,css,js}',
    '!' + production + '/feed.xml'
  ],
  dest: production
}

I replace these paths in files I know could contain paths to assets. Don’t include any images or binary files. The revision collector will try to open them and destroy binary files.

gulp/tasks/production/rev-collector.js

var gulp = require("gulp");
var collect = require("gulp-rev-collector");
var config = require("../../config").collect;

/**
 * Replace all links to assets in files
 * from a manifest file
 */
gulp.task("rev:collect", function () {
  return gulp.src(config.src).pipe(collect()).pipe(gulp.dest(config.dest));
});

This task will look into the manifest.json file and replace every path to one of the assets in every HTML, CSS, JavaScript, and Text.

The production build is finished! Only one thing is missing to complete this series of tutorials about Gulp.js: Deploying the Website to my server.

Conclusion

This concludes the 13th part of my series, Introduction to Gulp.js. Today we learned how to revise the asset files and replace links to these files.