Skip to content

Instantly share code, notes, and snippets.

@jbmoelker
Created March 12, 2017 14:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbmoelker/93b33208f3b5b45595ce595bcd78cf32 to your computer and use it in GitHub Desktop.
Save jbmoelker/93b33208f3b5b45595ce595bcd78cf32 to your computer and use it in GitHub Desktop.
Immutable caching of static assets with Express.js and Service Worker

Immutable caching of static assets with Express.js and Service Worker

This recipe revisions all asset files in a dist/assets/ directory using gulp-rev. The adds a unique content based hash to each asset file. The pattern of that hash (/.*-[0-9a-f]{10}\..*/) is then used to handle these files in Express.js and the Service Worker. Express.js sets the Cache-Control header to immutable. The Service Worker serves these files directly from cache without ever attempting the server again.

const gulp = require('gulp');
const filter = require('gulp-filter');
const rev = require('gulp-rev');
const revdel = require('gulp-rev-delete-original');
const override = require('gulp-rev-css-url');
const baseDir = 'dist/assets/';
const manifestFilename = 'rev-manifest.json';
const hashPattern = /.*-[0-9a-f]{10}\..*/;
gulp.src([
baseDir + '**/*.{css,css.map,js}',
baseDir + '**/*.{gif,jpg,png,svg,webp}',
baseDir + '**/*.{woff,woff2}'
])
.pipe(filter(file => !hashPattern.test(file.path)))
.pipe(filter(file => !file.path.endsWith('/sw.js')))
.pipe(rev())
.pipe(override())
.pipe(revdel())
.pipe(gulp.dest(baseDir))
.pipe(rev.manifest(manifestFilename))
.pipe(gulp.dest(baseDir));
const express = require('express');
const app = express();
app.use('/assets', (req, res, next) => {
// only set caching header on hashed files
const hashPattern = /.*-[0-9a-f]{10}\..*/;
const isHashedFilename = hashPattern.test(req.url);
if (isHashedFilename) {
const oneYear = 365 * 24 * 60 * 60;
res.setHeader('Cache-Control', 'max-age=' + oneYear + ', immutable');
}
next();
});
app.use('/assets', express.static('dist/assets/'));
app.listen(process.env.PORT);
importScripts('/sw-toolbox.js'); // https://github.com/GoogleChrome/sw-toolbox/
const prefix = 'project-v1';
toolbox.router.get('assets/*', req => {
const staticFilePattern = /.*-[0-9a-f]{10}\..*/;
if (staticFilePattern.test(req.url)) {
return toolbox.cacheFirst(req, [], {
cache: {
name: `${prefix}-static`,
maxEntries: 1000
}
});
}
return toolbox.networkOnly(req);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment