I am designing a website using PHP and MySQL, and I am having trouble creating a Service Worker that works the way I want.
My setup/requirements:
I have a menu page that offers links like /myevents/dataEntry.php?event=2024abcd and /myevents/dataEntry.php?event=2024efgh. The specific event keys are loaded from an external API into the database, so they are not known ahead of time.
The dataEntry.php page itself is mostly the same regardless of the parameter, but there is one <select> control whose options are populated from the database, server-side (having been populated from the API as well).
I need each event's dataEntry.php page to be available offline, once it's loaded. That is, at some point I would need to be online to load dataEntry.php?event=2024abcd the first time, but once I load it once, I want to be able to load that page again even if I'm offline. Since every event parameter results in a different list of options in the select control, each page/event combination needs to be cached separately.
What I've Tried:
My approach was to create a different service worker for each page/event, by using <script src="offlineWorker.js.php?event=<?php echo ($_GET['event']); ?>> in /myevents/dataEntry.php
(which would render as <script src="offlineWorker.js.php?event=2024abcd"> in the HTML).
The service worker that I've cobbled together (/myevents/offlineworker.js.php) is as follows:
<?php
header('Content-type: text/javascript');
if ( isset($_GET["event"]) ) {
?>
const cacheName = "event-<?php echo $_GET["event"]; ?>";
const precacheResources = [
"/myevents/dataEntry.php?event=<?php echo $_GET["event"]; ?>",
"/assets/css/theme.css"
];
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/myevents/offlineWorker.js.php?event=<?php echo $_GET["event"]; ?>')
.then(() => console.log("Successfully registered service worker after window loaded."));
});
}
self.addEventListener('install', (event) => {
event.waitUntil((async () => {
const cache = await caches.open(cacheName);
await cache.addAll(precacheResources);
})());
});
self.addEventListener('fetch', (event) => {
const requestURL = new URL(event.request.url);
if(!(event.request.url.startsWith('http'))) {
// skip request for things like plugins while you're offline.
} else if (precacheResources.includes(requestURL.pathname) || precacheResources.includes(requestURL.pathname + requestURL.search)) {
event.respondWith((async () => {
// try the cache first
const r = await caches.match(event.request);
if (r) { return r; }
// cache the new resource and return it
const response = await fetch(event.request);
const cache = await caches.open(cacheName);
cache.put(event.request, response.clone());
return response;
})());
}
});
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheList => {
return Promise.all(
cacheList.filter(thisCache => {
return thisCache !== cacheName;
}).map(thisCache => {
return caches.delete(thisCache);
})
);
})
);
});
<?php
}
?>
The idea is that each event would have its OWN service worker, caching the specific dataEntry page and the css file I need for the page. Each cache has its own name as well.
My Problem
Unfortunately, although the service worker is registered (correctly, as far as I can tell), and I can confirm that the .css file is cached and available offline, the /myevents/dataEntry.php?event=2024abcd page is not.
My best guesses as to why are that perhaps:
- Only a single service worker per domain might be able to be registered
- Service workers cannot be registered with a URL Parameter (ChatGPT suggests this is the case, though I'm dubious, especially since the css file is properly cached)
- Cached files cannot have URL Parameters in their paths.
I'm hoping the answer is simply a mistake I've made rather than any of these three, since I'm not sure how I'd get around those issues if they're true :)
Thank you for your attention and thoughts!