0

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:

  1. Only a single service worker per domain might be able to be registered
  2. 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)
  3. 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!

3
  • Check the Service Workers in the Application tab in the developer tools - how many do you see for your domain Commented Aug 24, 2024 at 2:19
  • I loaded up a fresh browser environment to check. When I load the first page, I only see one. And if I click "See All Registrations" under "Service workers from other origins" and search the page, I only see one service worker for my domain. Then I loaded a second event (changed the parameter). Now I see the first service worker still, and a second service worker that is "waiting to activate". Does the fact that I still see the first service worker on this new page mean that I'm not creating a separate service worker after all? 🤔 Commented Aug 24, 2024 at 4:06
  • I’ve realized a big part of my problem is in my php where I’m echoing the event parameter value; I didn’t have the contents wrapped in parentheses so nothing was getting echoed, meaning the cache name and path of my page were invalid. Now I’m wondering if my approach was wrong though; I’m feeling like I could have a single service worker and multiple caches… or after testing it looks like I could even just have a single cache and each page I visit would just add to the list of pages available in the cache. I’ll update my final code here in case it helps anyone but I welcome other thoughts! Commented Aug 26, 2024 at 5:04

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.