I've found this solution works for iOS Safari and other browsers ...
It performs a window.location.reload(true)
to force the page to reload avoiding use of caching whenever it detects that the cached web app or web page does not match the server's version.
You really want this mechanism in place before you publish the first version of your site as otherwise once it's out there you can no longer rely on ever upgrading your iOS users. This is a nightmare if you rely on client app and server versions being in sync. Sigh ... Sadly it seems Safari and iOS Safari in particular is eager to take the throne once held by Internet Explorer.
During deployment
- Increment and save a build number.
- I use a
version.json
file that looks like {"major":1,"minor":0,"patch":0,"build":12}
- Copy
version.json
to both client and server apps.
On server:
- Write a server API in PHP/Node/Ruby/C# that returns the server's
version.json
- Use web server rules and response headers to prevent API results being cached.
In client app or web page:
- To diagnose issues, display the client version + client and server build numbers.
Call on page load ...
function onload() {
var clientVersion = require("./version.json");
// Might replace axios with new fetch() API or older XMLHttpRequest
axios.get("/api/version").then(function(res) {
var serverVersion = res.data;
var lastReload = parseInt(localStorage.getItem("lastReload") || "0");
var now = new Date().getTime();
if (
serverVersion.build !== clientVersion.build &&
now - lastReload > 60 * 1000 // Prevent infinite reloading.
) {
localStorage.setItem("lastReload", now);
window.location.reload(true); // force page reload
}
});
}
You might prefer to test serverVersion.build > clientVersion.build
rather than serverVersion.build !== clientVersion.build
. The benefit of testing !==
is that it allows you not only upgrade the version but also roll back a version and ensure clients get rolled back as well.
In the event that the client and server build numbers are mismatched I prevent the client from infinitely reloading by only performing a single reload within 60 secs.
Note that this method is only concerned with matching build numbers (= deployment number) you might prefer something more sophisticated.
Here's a simple node app to increment a build number.
const APP_DATA = "../app/src/assets"; // client folder
const FUNC_DATA = "../functions/data"; // server folder
var log = require("debug")("build:incr");
var fs = require("fs");
function readJson(path) {
log(`Reading: ${path}`);
const text = fs.readFileSync(path);
return JSON.parse(text);
}
function writeJson(path, json) {
log(`Writing: ${path}`);
fs.writeFileSync(path, JSON.stringify(json));
}
let version = readJson("./version.json");
version.build++;
log("Version = ", version);
writeJson("./version.json", version);
writeJson(`${APP_DATA}/version.json`, version);
writeJson(`${FUNC_DATA}/version.json`, version);