ssuhat
ssuhat

Reputation: 7656

React SPA force load new JS build (including mobile)

I'm currently experiencing every time I build script for production , the browser won't load any new JS.

I'm using create-react-app. The only way to make it work is clear cache manually.

I've tried to put window.location.reload(true) but it still won't fetch latest JS.

and then I try to put this on my index.html

<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />

none of them is working.

The browser won't load any new JS especially for mobile (Chrome Android, Firefox).

I'm using Cloudflare and I already try to purge cache.

Any other solution to force the browser load new script?

Thanks

Upvotes: 5

Views: 3284

Answers (3)

Gary Vernon Grubb
Gary Vernon Grubb

Reputation: 11215

Add this code to registerServiceWorker.js. It will reload the page once a new service worker is activated. I usually add it inside the registerValidSW function as shown below:

    function registerValidSW(swUrl) {

    //Reload once the new service worker is activated.
      var refreshing;
      navigator.serviceWorker.addEventListener('controllerchange',
        function () {
          if (refreshing) return;
          refreshing = true;
          window.location.reload();
        }
      );


//Below code is create-react-app default
      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.');
                  // window.location.reload(true);
                } 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);
        });
    }

I noticed that with create-react-app, often successive builds ended up with the same hashed file name. This was causing the app to reuse the old cached files.

To resolve, I rename the old build directory to 'build.old' and then run a fresh build. This way there is a very slim chance that the build will reuse an old file name.

Once build is done, add the below link to service-worker.js:

self.skipWaiting();

This will force the new service worker to be activated even while the existing one is still running.

Add Below headers to both your index.html & service-worker.js:

cache-control: max-age=0,no-cache,no-store,must-revalidate

Upvotes: 1

Miniver Cheevy
Miniver Cheevy

Reputation: 1677

I believe the cache attributes will only effect the index.html not it's dependent files. To do this with java script files you'd have to do something server side to write those values into the response header. You could try adding query string to the end of your script references something like

<script src='/dist/main.js?v=123'></script>

and increment that version number with each release.

If you're feeling bold you could add hashing to your filenames. This would require ejecting your configuration from create-react-app and isn't a step to take likely. You could also look into one of the somewhat dicey methods of customizing the webpack configuration without ejecting.

Upvotes: 0

Richard
Richard

Reputation: 1046

A common method is to put a unique hash in the JS file so the browser goes off and fetches what it believes to be a completely different file from what was there before.

If you're using Webpack (as I assume you are with create-react-app) then you can add [hash] into your output JS file name:

output: {
    filename: 'bundle.[hash].js',
},

Upvotes: 2

Related Questions