Compare commits

...

3 Commits

Author SHA1 Message Date
peshomir 401499fa0e Fix missing word in changelog 2025-07-15 23:19:44 +03:00
peshomir 315aa5ff68 Bump version 2025-07-15 23:14:03 +03:00
peshomir 3a34d2f83e Service worker code refactoring; hopefully fix stale cache errors 2025-07-15 23:13:19 +03:00
6 changed files with 169 additions and 131 deletions

View File

@ -12,7 +12,7 @@ fs.cpSync("./static/", "./build/", { recursive: true });
fs.cpSync("./assets/", "./build/assets/", { recursive: true });
const buildTimestamp = Date.now().toString();
fs.writeFileSync("./build/index.html", fs.readFileSync("./build/index.html").toString().replace(/buildTimestamp/g, buildTimestamp));
fs.writeFileSync("./build/sw.js", fs.readFileSync("./build/sw.js").toString().replace("buildTimestamp", buildTimestamp));
fs.writeFileSync("./build/sw2.js", fs.readFileSync("./build/sw2.js").toString().replace("buildTimestamp", buildTimestamp));
const buildClientCode = () => /** @type {Promise<void>} */(new Promise((resolve, reject) => {
console.log("Building client code...");

View File

@ -1,17 +1,6 @@
import versionData from '../version.json';
const { version, lastUpdated } = versionData;
if ("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", (e) => {
const message = e.data;
if (message.event === "activate" && buildTimestamp !== message.version) {
// worker was updated in the background
document.getElementById("updateNotification").style.display = "block";
}
});
navigator.serviceWorker.register("./sw.js");
}
import settingsManager from './settings.js';
import { clanFilter, leaderboardFilter } from "./clanFilters.js";
import WindowManager from "./windowManager.js";

View File

@ -1,8 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Google tag (gtag.js) -->
<!--<script async src="https://www.googletagmanager.com/gtag/js?id=G-WYYDMY13BG"></script>
<!--<script async src="https://www.googletagmanager.com/gtag/js?id=G-WYYDMY13BG"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
@ -55,11 +56,49 @@
color: rgb(225, 225, 255);
}
</style>
<script>
// adapted from https://stackoverflow.com/a/44593894 and https://stackoverflow.com/a/40446448
function showUpdatePrompt(/** @type {ServiceWorker} */ sw) {
console.log("showing update prompt")
document.getElementById("updateNotification").style.display = "block";
document.getElementById("swUpdateButton").addEventListener("click", () => {
sw.postMessage({ update: true });
})
}
document.addEventListener("DOMContentLoaded", function () {
if (!("serviceWorker" in navigator)) return;
navigator.serviceWorker.addEventListener("controllerchange", () => {
console.log("Controlling service worker changed, refreshing page");
window.location.reload();
});
navigator.serviceWorker.register("./sw2.js").then(function (registration) {
if (!navigator.serviceWorker.controller) return;
// if there's an updated worker already waiting, update
if (registration.waiting) return showUpdatePrompt(registration.waiting);
// if a worker in the "installing" state becomes "installed", update
function handleInstalling() {
var sw = registration.installing;
sw.addEventListener("statechange", function () {
if (sw.state === "installed") showUpdatePrompt(sw);
})
}
// if there's an updated worker installing, track its progress
if (registration.installing) handleInstalling();
// otherwise, listen for new workers arriving
registration.addEventListener('updatefound', handleInstalling);
});
});
</script>
</head>
<body onload="aiCommand746(0);">
<canvas id="canvasA" width="128" height="128"></canvas>
<span id="windowContainer"><div class="window flex-column settings" style="display:none">
<span id="windowContainer">
<div class="window flex-column settings" style="display:none">
<h1>Settings</h1>
<div class="scrollable"></div>
<hr>
@ -77,20 +116,26 @@
</div>
<div class="window scrollable selectable" id="playerlist" style="display: none;">
<h1>Player List</h1>
<table><tbody id="playerlist_content"></tbody></table>
<table>
<tbody id="playerlist_content"></tbody>
</table>
</div>
<div class="window scrollable selectable" id="donationhistory" style="display:none">
<h1>Donation history for </h1>
<p id="donationhistory_note">Note: donations from bots are not shown here</p>
<table><tbody id="donationhistory_content"></tbody></table>
<table>
<tbody id="donationhistory_content"></tbody>
</table>
</div>
<div class="window" style="display: none" id="updateNotification">
<h3>A new version of FX is available! Reload to update</h3>
<button onclick="window.location.reload()">Reload</button>
<button id="swUpdateButton">Reload</button>
<button onclick="document.getElementById('updateNotification').style.display = 'none'">Dismiss</button>
</div></span>
</div>
</span>
<script src="variables.js?buildTimestamp"></script>
<script src="fx.bundle.js?buildTimestamp"></script>
<script src="game.js?buildTimestamp"></script>
</body>
</html>

View File

@ -1,47 +1 @@
const cacheName = "buildTimestamp"; // this gets replaced by the build script
self.addEventListener("install", (e) => {
console.log("[Service Worker] Install");
self.skipWaiting();
});
self.addEventListener("fetch", (e) => {
const url = e.request.url;
// Cache http and https only, skip unsupported chrome-extension:// and file://...
if (!(url.startsWith('http:') || url.startsWith('https:'))) {
return;
}
e.respondWith(
(async () => {
const r = await caches.match(e.request);
console.log(`[Service Worker] Fetching resource: ${url}`);
if (r) {
return r;
}
const response = await fetch(e.request);
const cache = await caches.open(cacheName);
console.log(`[Service Worker] Caching new resource: ${url}`);
cache.put(e.request, response.clone());
return response;
})(),
);
});
self.addEventListener("activate", (e) => {
console.log("[Service Worker] Activated", cacheName);
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({ event: "activate", version: cacheName }));
});
e.waitUntil(
caches.keys().then((keyList) => {
return Promise.all(
keyList.map((key) => {
if (key === cacheName) {
return;
}
return caches.delete(key);
}),
);
}),
);
});
// removed

51
static/sw2.js 100644
View File

@ -0,0 +1,51 @@
const cacheName = "buildTimestamp"; // this gets replaced by the build script
self.addEventListener("install", (e) => {
console.log("[Service Worker] Install", cacheName);
});
self.addEventListener('message', function (e) {
if (e.data.update) {
self.skipWaiting();
}
});
self.addEventListener("fetch", (e) => {
const url = e.request.url;
// Cache http and https only, skip unsupported chrome-extension:// and file://...
if (!(url.startsWith('http:') || url.startsWith('https:'))) {
return;
}
e.respondWith(
(async () => {
const cache = await caches.open(cacheName);
const r = await cache.match(e.request);
console.log(`[Service Worker] Fetching resource: ${url}`);
if (r) {
return r;
}
const response = await fetch(e.request);
console.log(`[Service Worker] Caching new resource: ${url}`);
cache.put(e.request, response.clone());
return response;
})(),
);
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({ event: "activate", version: cacheName }));
});
});
self.addEventListener("activate", (e) => {
console.log("[Service Worker] Activated", cacheName);
e.waitUntil(
caches.keys().then((keyList) => {
return Promise.all(
keyList.map((key) => {
if (key === cacheName) {
return;
}
return caches.delete(key);
}),
);
}),
);
});

View File

@ -1,8 +1,7 @@
{
"version": "0.6.11",
"lastUpdated": "Jul 14",
"version": "0.6.12",
"lastUpdated": "Jul 15",
"changes": [
"Fix for game update 2.09.0",
"Error reporting improvements"
"Refactored the service worker code to (hopefully) fix a ton of relatively rare errors related to how the client's files are loaded (for example, code from earlier versions would sometimes be loaded along with code from newer versions, causing all kinds of issues). FX Client should be much more stable after this change."
]
}