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