Creating a PWA for GeoGebra Applets so that they work offline without needing internet connection

121 Views Asked by At

I want to build a pwa website that will host offline geogebra applets without need the user to have geogebra installed. I have already built a working local website but it needs internet for the geogebra applets to work. I want the Geogebra applets to work offline, not to require internet connection.

I have already built a locally hosted website and also converted it to an apk using cordova. The website or the app works work well when online.

I have tried creating a pwa website version and it works well. The service works are fine and I score above 80% on lighthouse but the problem is that the pwa doesn't back or store the geogebra applets so that they work when offline.

How do I achieve what I want. Below is my Service Workers Code:

// sw.js - Service Worker

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open('app-cache').then((cache) => {
            return cache.addAll([
                '/',
                'index.html',
                'styles.css',
                'script.js',
                'manifest.json',
                'offline.html',
                '/STEAM/steamApp1.html',
                'https://www.geogebra.org/m/kkdqjbxa',
                // Add other resources here as needed
            ]);
        })
    );
});

self.addEventListener('fetch', (event) => {
    // Handle GeoGebra applets separately using a proxy server
    if (event.request.url.startsWith('https://www.geogebra.org/')) {
        event.respondWith(
            fetch(event.request)
                .then((fetchResponse) => {
                    // Check if the response is valid and cacheable
                    if (!fetchResponse || fetchResponse.status !== 200 || fetchResponse.type !== 'basic') {
                        return fetchResponse;
                    }

                    const responseToCache = fetchResponse.clone();

                    caches.open('app-cache').then((cache) => {
                        cache.put(event.request, responseToCache);
                    });

                    return fetchResponse;
                })
                .catch((error) => {
                    console.error('Fetch error:', error);

                    // Respond with the offline page as a fallback
                    return caches.match('offline.html'); // Update with the correct path
                })
        );
    } else {
        // Handle other requests using cache
        event.respondWith(
            caches.match(event.request).then((response) => {
                if (response) {
                    return response;
                }

                return fetch(event.request)
                    .then((fetchResponse) => {
                        // Check if the response is valid and cacheable
                        if (!fetchResponse || fetchResponse.status !== 200 || fetchResponse.type !== 'basic') {
                            return fetchResponse;
                        }

                        const responseToCache = fetchResponse.clone();

                        caches.open('app-cache').then((cache) => {
                            cache.put(event.request, responseToCache);
                        });

                        return fetchResponse;
                    })
                    .catch((error) => {
                        console.error('Fetch error:', error);

                        // Respond with the offline page as a fallback
                        return caches.match('offline.html'); // Update with the correct path
                    });
            })
        );
    }
});

self.addEventListener('message', event => {
    if (event.data.type === 'my-message') {
        event.waitUntil(
            // Perform asynchronous operations here
            // and then send a response back to the main thread
            self.clients.matchAll().then(clients => {
                // Respond to the main thread
                clients.forEach(client => {
                    client.postMessage({ type: 'my-response', data: 'response-data' });
                });
            })
        );
    }
});


// service-worker.js

self.addEventListener('message', event => {
    if (event.data.type === 'perform-async-operation') {
        event.waitUntil(
            performAsyncOperation(event.data.payload)
                .then(result => {
                    // Respond to the main thread with a success message
                    self.clients.matchAll().then(clients => {
                        clients.forEach(client => {
                            client.postMessage({ type: 'async-operation-result', success: true, data: result });
                        });
                    });
                })
                .catch(error => {
                    // Respond to the main thread with an error message
                    self.clients.matchAll().then(clients => {
                        clients.forEach(client => {
                            client.postMessage({ type: 'async-operation-result', success: false, error: error.message });
                        });
                    });
                })
        );
    }
});

function performAsyncOperation(payload) {
    return new Promise((resolve, reject) => {
        // Simulate an async operation, e.g., fetching data from a remote server
        setTimeout(() => {
            const randomValue = Math.random();
            if (randomValue > 0.5) {
                resolve(`Async operation successful with payload: ${JSON.stringify(payload)}`);
            } else {
                reject(new Error('Async operation failed'));
            }
        }, 2000); // Simulate a delay
    });
}


JavaScript:
// script.js - Handling info button click and service worker registration
document.addEventListener("DOMContentLoaded", function () {
    const infoButtons = document.querySelectorAll(".info-button");

    infoButtons.forEach(button => {
        button.addEventListener("click", function (event) {
            event.preventDefault();
            const applet = button.closest(".applet");
            applet.classList.toggle("info-open");
        });
    });

    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('sw.js')
            .then((registration) => {
                console.log('Service Worker registered with scope:', registration.scope);
            })
            .catch((error) => {
                console.log('Service Worker registration failed:', error);
            });
    }
});

// Service worker fetch event handling
self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((response) => {
            if (response) {
                return response;
            }

            return fetch(event.request).then((response) => {
                if (!response || response.status !== 200 || response.type !== 'basic') {
                    return response;
                }

                const responseToCache = response.clone();

                caches.open('app-cache').then((cache) => {
                    cache.put(event.request, responseToCache);
                });

                return response;
            });
        }).catch((error) => {
            console.error('Fetch error:', error);
            // You can provide a fallback response here if needed.
        })
    );
});
self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((response) => {
            if (response) {
                return response;
            }

            return fetch(event.request)
                .then((response) => {
                    // Check if the response is valid and cacheable
                    if (!response || response.status !== 200 || response.type !== 'basic') {
                        return response;
                    }

                    const responseToCache = response.clone();

                    caches.open('app-cache').then((cache) => {
                        cache.put(event.request, responseToCache);
                    });

                    return response;
                })
                .catch((error) => {
                    console.error('Fetch error:', error);

                    // Respond with the offline page as a fallback
                    return caches.match('offline.html'); // Update with the correct path
                });
        })
    );
});

// script.js - Handling info button click and service worker registration
document.addEventListener("DOMContentLoaded", function () {
    const infoButtons = document.querySelectorAll(".info-button");

    infoButtons.forEach(button => {
        button.addEventListener("click", function (event) {
            event.preventDefault();
            const applet = button.closest(".applet");
            applet.classList.toggle("info-open");
        });
    });

    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('sw.js')
            .then((registration) => {
                console.log('Service Worker registered with scope:', registration.scope);
            })
            .catch((error) => {
                console.log('Service Worker registration failed:', error);
            });
    }
});
0

There are 0 best solutions below