From de9459dd83507cb80de643529c5595563cf3fe74 Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Fri, 8 Mar 2019 12:29:49 +0200 Subject: [PATCH] Implement cache busting based on version hash --- client/index.html.tpl | 15 ++++++++------- client/service-worker.js | 28 +++++++++++++++------------- src/helper.js | 8 ++++++++ src/server.js | 5 ++++- webpack.config.js | 13 ++++++++++++- 5 files changed, 47 insertions(+), 22 deletions(-) diff --git a/client/index.html.tpl b/client/index.html.tpl index 92db1ef8..4e4bc182 100644 --- a/client/index.html.tpl +++ b/client/index.html.tpl @@ -5,11 +5,12 @@ - - + + + - - + + <% _.forEach(stylesheets, function(css) { %> @@ -59,7 +60,7 @@

This is taking longer than it should, there might be connectivity issues.

- +
@@ -68,7 +69,7 @@
- - + + diff --git a/client/service-worker.js b/client/service-worker.js index e05df454..aa36f885 100644 --- a/client/service-worker.js +++ b/client/service-worker.js @@ -2,7 +2,7 @@ /* global clients */ "use strict"; -const cacheName = "thelounge"; +const cacheName = "__HASH__"; const excludedPathsFromCache = /^(?:socket\.io|storage|uploads|cdn-cgi)\//; self.addEventListener("install", function() { @@ -10,6 +10,12 @@ self.addEventListener("install", function() { }); self.addEventListener("activate", function(event) { + event.waitUntil(caches.keys().then((names) => Promise.all( + names + .filter((name) => name !== cacheName) + .map((name) => caches.delete(name)) + ))); + event.waitUntil(self.clients.claim()); }); @@ -33,34 +39,30 @@ self.addEventListener("fetch", function(event) { return; } - const uri = new URL(url); - uri.hash = ""; - uri.search = ""; - - event.respondWith(networkOrCache(event, uri)); + event.respondWith(networkOrCache(event)); }); -async function putInCache(uri, response) { +async function putInCache(request, response) { const cache = await caches.open(cacheName); - await cache.put(uri, response); + await cache.put(request, response); } -async function networkOrCache(event, uri) { +async function networkOrCache(event) { try { - const response = await fetch(uri, {cache: "no-cache"}); + const response = await fetch(event.request, {cache: "no-cache"}); if (response.ok) { - event.waitUntil(putInCache(uri, response)); + event.waitUntil(putInCache(event.request, response)); return response.clone(); } throw new Error(`Request failed with HTTP ${response.status}`); } catch (e) { // eslint-disable-next-line no-console - console.error(e.message, uri.href); + console.error(e.message, event.request.url); const cache = await caches.open(cacheName); - const matching = await cache.match(uri); + const matching = await cache.match(event.request); return matching || Promise.reject("request-not-in-cache"); } diff --git a/src/helper.js b/src/helper.js index d2f96f51..e34922f7 100644 --- a/src/helper.js +++ b/src/helper.js @@ -9,6 +9,7 @@ const fs = require("fs"); const net = require("net"); const bcrypt = require("bcryptjs"); const colors = require("chalk"); +const crypto = require("crypto"); let homePath; let configPath; @@ -32,6 +33,7 @@ const Helper = { getUserLogsPath, setHome, getVersion, + getVersionCacheBust, getGitCommit, ip2hex, mergeConfig, @@ -89,6 +91,12 @@ function getGitCommit() { } } +function getVersionCacheBust() { + const hash = crypto.createHash("sha256").update(Helper.getVersion()).digest("hex"); + + return hash.substring(0, 10); +} + function setHome(newPath) { homePath = expandHome(newPath); configPath = path.join(homePath, "config.js"); diff --git a/src/server.js b/src/server.js index ac18037f..c3f18cb4 100644 --- a/src/server.js +++ b/src/server.js @@ -281,7 +281,10 @@ function index(req, res, next) { throw err; } - res.send(_.template(file)(getServerConfiguration())); + const config = getServerConfiguration(); + config.cacheBust = Helper.getVersionCacheBust(); + + res.send(_.template(file)(config)); }); } diff --git a/webpack.config.js b/webpack.config.js index b168c280..08c0815a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -5,6 +5,7 @@ const path = require("path"); const CopyPlugin = require("copy-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const VueLoaderPlugin = require("vue-loader/lib/plugin"); +const Helper = require("./src/helper.js"); const config = { mode: process.env.NODE_ENV === "production" ? "production" : "development", @@ -123,7 +124,17 @@ const config = { { from: "./client/*", to: "[name].[ext]", - ignore: "index.html.tpl", + ignore: [ + "index.html.tpl", + "service-worker.js", + ], + }, + { + from: "./client/service-worker.js", + to: "[name].[ext]", + transform(content) { + return content.toString().replace("__HASH__", Helper.getVersionCacheBust()); + }, }, { from: "./client/audio/*",