Steve Temple
Technical Director of Gibe Developer, Umbraco MVP/Certified Master/Unicore Team e-commerce expert, AI tinkerer
An automated system for invalidating cache at build time
No manual involvement
If the file hasn't changed the user's cache is kept
Not adding anything except CSS/JS/Image changes to commit history
Not querystring based but filename based
This will take one or more files and create a copy of those files including a hash of the file in the filename.
e.g. /css/site.css becomes /css/site-273c2cin3f.css
Hashes are important because if the file hasn't change the version hash will stay the same
It will then create a JSON manifest file listing the changes:
{
"css/site.js": "css/site-273c2cin3f.css",
"js/site.js": "js/site-d41d8cd98f.js"
}
A pure Gulp solution using gulp-rev, gulp-rev-delete and gulp-rev-replace
Got us 80% of the way there but .cshtml files have to be updated whenever CSS changes
var gulp = require('gulp'),
bower = require('gulp-bower'),
sass = require('gulp-sass'),
sourcemaps = require('gulp-sourcemaps'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
rev = require('gulp-rev'),
revdel = require('gulp-rev-delete-original'),
revReplace = require('gulp-rev-replace'),
filter = require('gulp-filter');
gulp.task('css', function () {
return gulp.src('./gulp/scss/**/*.scss')
.pipe(sourcemaps.init())
.pipe(sass({ outputStyle: 'compressed' }))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./css'))
.pipe(filter('**/*.css'))
.pipe(rev())
.pipe(revdel())
.pipe(gulp.dest('./css'))
.pipe(rev.manifest())
.pipe(gulp.dest('./css'));
});
gulp.task('revreplace', ['css'], function () {
var manifest = gulp.src("./css/rev-manifest.json");
return gulp.src('./views/shared/stylesheets.template.cshtml')
.pipe(revReplace({ manifest: manifest, replaceInExtensions: ['.cshtml'] }))
.pipe(gulp.dest('./views/shared/stylesheets.cshtml'));
});
A mixed Gulp and C# solution to do the revisions at build time but pick up the manifests at run time.
var gulp = require('gulp'),
bower = require('gulp-bower'),
sass = require('gulp-sass'),
sourcemaps = require('gulp-sourcemaps'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
rev = require('gulp-rev'),
revdel = require('gulp-rev-delete-original'),
filter = require('gulp-filter');
gulp.task('css', function () {
return gulp.src('./gulp/scss/**/*.scss')
.pipe(sourcemaps.init())
.pipe(sass({ outputStyle: 'compressed' }))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('./css'))
.pipe(filter('**/*.css'))
.pipe(rev())
.pipe(revdel())
.pipe(gulp.dest('./css'))
.pipe(rev.manifest())
.pipe(gulp.dest('./css'));
});
Install-Package Gibe.CacheBusting
<section name="cacheBusting" type="Gibe.CacheBusting.Config.CacheBustingSection,
Gibe.CacheBusting" />
<cacheBusting>
<manifests>
<add path="/css/" file="~/css/rev-manifest.json" />
<add path="/js/" file="~/js/rev-manifest.json" />
</manifests>
</cacheBusting>
<link rel="stylesheet" href="@Url.Asset("/css/site.css")" />
Will end up like:
<link rel="stylesheet" href="/css/site-273c2cin3f.css" />
Now you can use it like this:
Cached so it loads once on site load and then keeps the manifest in memory
Uses a dictionary to do the lookup internally so is super fast lookup
If the entry isn't found returns the URL that was passed in
Monitors the file system so if a manifest file changes then it loads the new version
A mix of the 2:
Static images (sprites etc) are changed and the CSS is updated using gulp-rev-replace
CSS and JS are updated using gulp-rev but the URLs are using the Gibe.CacheBusting library
https://github.com/sindresorhus/gulp-rev
https://github.com/jamesknelson/gulp-rev-replace
https://github.com/Gibe/Gibe.CacheBusting
By Steve Temple
A demonstration of cache busting using Gulp-Rev and a custom C# package
Technical Director of Gibe Developer, Umbraco MVP/Certified Master/Unicore Team e-commerce expert, AI tinkerer