Managing Static Asset Caching with Gulp

During frontend application updates, browsers often serve outdated cached assets like CSS or JavaScript files, leading to broken layouts or unexpected behavior—even when the deployed code is correct. This occurs because browsers load resources marked as from cache, bypassing the server entirely.

To ensure users always receive the latest version of an asset after a deployment, the browser must be forced to fetch it anew. A naive approach involves manually renaming files (e.g., a.cssa-1221.css) and updating all HTML references—a tedious and error-prone process, especially in large projects.

Automated Cache Busting with Gulp Plugins

The gulp-rev plugin solves this by appending a content-based hash to filenames. When a file changes, its hash changes, producing a new filename:

{
  "base/index.css": "base/index-c52f09f203.css"
}

Sample Gulp task:

const gulp = require('gulp');
const rev = require('gulp-rev');

gulp.task('hash-assets', () => {
  return gulp.src('src/css/*.css')
    .pipe(rev())
    .pipe(rev.manifest())
    .pipe(gulp.dest('build/rev'));
});

However, this only renames files—it doesn’t update references in HTML. That’s where gulp-rev-collector comes in. It reads the manifest and rewrites asset paths in HTML templates:

const revCollector = require('gulp-rev-collector');

gulp.task('update-html', () => {
  return gulp.src(['build/rev/*.json', 'src/views/*.html'])
    .pipe(revCollector())
    .pipe(gulp.dest('dist/views'));
});

Note: gulp-rev already handles file renaming during the pipeline, so an extra gulp-rename step is unnecessary if assets are processed through rev() before being written to disk.

Query String–Based Versioning

In non-SPA or server-rendered applications, renaming files may be impractical. An alternative is appending a version query parameter:

<link rel="stylesheet" href="/css/style.css?v=c52f09f203">

While the filename stays the same, the changing query string (?v=...) forces the browser to treat it as a new resource. The gulp-rev-query and gulp-rev-collector-query plugins support this pattern, though some versions mishandle minified files (e.g., .min.css).

A corrected transform stream can fix this by adjusting the regex to properly parse hashed filenames:

const through = require('through2');

module.exports = function(versionParam = 'v') {
  return through.obj((file, enc, cb) => {
    const content = file.contents.toString();
    const updated = content.replace(
      /(["'])([^"']+)-([a-f0-9]{7,10})(\.\w+)(["'])/g,
      (match, q1, path, hash, ext, q2) => `${q1}${path}${ext}?${versionParam}=${hash}${q2}`
    );
    file.contents = Buffer.from(updated);
    cb(null, file);
  });
};

This approach ensures reliable cache invalidation without altering directory structure, making it suitable for traditional web applications.

Tags: gulp asset-cache-busting frontend-build-tools

Posted on Sat, 23 May 2026 22:24:22 +0000 by karldesign