Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exclude index.html from service worker cache in create-react-app

I have a reactJs app using create-react-app. The app uses service-worker and other PWA features but somehow I am seeing that despite updating the website or deploying a new build, chrome always picks index.html from service worker and does not make a network call at all.

I think caching the index.html using the service worker is the issue but have not been able to exclude it from getting cached, I did check a few questions on SO and issues on github but could not get a fix for this.

I am using the default service-worker registration

registerServiceWorker.js

// In production, we register a service worker to serve assets from local cache.

// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.


// This link also includes instructions on opting out of this behavior.

const isLocalhost = Boolean(
    window.location.hostname === 'localhost' ||
    // [::1] is the IPv6 localhost address.
    window.location.hostname === '[::1]' ||
    // 127.0.0.1/8 is considered localhost for IPv4.
    window.location.hostname.match(
        /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
    )
);

export default function register() {

    if (/*process.env.NODE_ENV === 'production' &&*/ 'serviceWorker' in navigator) {
       // alert('found' + process.env.NODE_ENV);
        // The URL constructor is available in all browsers that support SW.
        const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
        if (publicUrl.origin !== window.location.origin) {
            // Our service worker won't work if PUBLIC_URL is on a different origin
            // from what our page is served on. This might happen if a CDN is used to
            // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
            return;
        }

        window.addEventListener('load', () => {
            const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

            if (isLocalhost) {
                // This is running on localhost. Lets check if a service worker still exists or not.
                checkValidServiceWorker(swUrl);
            } else {
                // Is not local host. Just register service worker
                registerValidSW(swUrl);
            }
        });


    } else {
        //alert('not found' + process.env.NODE_ENV);
    }
}

function registerValidSW(swUrl) {
    navigator.serviceWorker
        .register(swUrl)
        .then(registration => {

            registration.onupdatefound = () => {
                const installingWorker = registration.installing;

                installingWorker.onstatechange = () => {
                    if (installingWorker.state === 'installed') {
                        if (navigator.serviceWorker.controller) {
                            // At this point, the old content will have been purged and
                            // the fresh content will have been added to the cache.
                            // It's the perfect time to display a "New content is
                            // available; please refresh." message in your web app.
                            console.log('New content is available; please refresh.');
                        } else {
                            // At this point, everything has been precached.
                            // It's the perfect time to display a
                            // "Content is cached for offline use." message.
                            console.log('Content is cached for offline use.');
                        }
                    }
                };
            };
        })
        .catch(error => {
            console.error('Error during service worker registration:', error);
        });
}

function checkValidServiceWorker(swUrl) {
    // Check if the service worker can be found. If it can't reload the page.
    fetch(swUrl)
        .then(response => {
            // Ensure service worker exists, and that we really are getting a JS file.
            if (
                response.status === 404 ||
                response.headers.get('Content-Type').indexOf('javascript') === -1
            ) {
                // No service worker found. Probably a different app. Reload the page.
                navigator.serviceWorker.ready.then(registration => {
                    registration.unregister().then(() => {
                        window.location.reload();
                    });
                });
            } else {
                // Service worker found. Proceed as normal.
                registerValidSW(swUrl);
            }
        })
        .catch(() => {
            console.log(
                'No internet connection found. App is running in offline mode.'
            );
        });
}

export function unregister() {
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.ready.then(registration => {
            registration.unregister();
        });
    }
}

Please help.

like image 761
Nayan Srivastava Avatar asked Nov 30 '18 19:11

Nayan Srivastava


2 Answers

If you have ejected from create-react-app you can go into /config/webpack.config.js and change the default arguments for GenerateSW() to the following:

new WorkboxWebpackPlugin.GenerateSW({
          clientsClaim: true,
          exclude: [/\.map$/, /asset-manifest\.json$/, /index.html/],
          importWorkboxFrom: "cdn",
          navigateFallbackBlacklist: [
            // Exclude URLs starting with /_, as they're likely an API call
            new RegExp("^/_"),
            // Exclude URLs containing a dot, as they're likely a resource in
            // public/ and not a SPA route
            new RegExp("/[^/]+\\.[^/]+$")
          ]

This way you don't have to manually change your serviceworker.js after every building.

like image 182
Tim von Känel Avatar answered Sep 21 '22 12:09

Tim von Känel


After trying multiple options, the one that worked best was not I was really willing to implement but could not find anything better.

From the service-worker.js file remove below lines

workbox.routing.registerNavigationRoute("/index.html", {

  blacklist: [/^\/_/,/\/[^\/]+\.[^\/]+$/],
});

This will not cache index.html and try to pull it every time from the server, though this does not sound best but does the trick.

like image 31
Nayan Srivastava Avatar answered Sep 18 '22 12:09

Nayan Srivastava