Search code examples
javascriptreactjscachingservice-workerworkbox

React application with Service Worker - Force update of browser cache on new version


My app is written in Reac / Redux and uses Workbox to generate my service worker. This works - I can confirm revision is updated in the generated service worker when running "workbox inject:manifest".

However, I have noticed clients are not updating the cache after a new release, new code will only load after several refreshes. For each release I have confirmed that the revision is updated.

The things I have tried so far to force the browser to clear the cache after a new release are:

  • Implemented skipWaiting() in my ServiceWorker - shows update alert correctly
  • Added cache headers to disable caching of the serviceWorker.js and css files (see below)
  • Added [contenthash] to all my bundle files in Webpack and updated index.html accordingly for each release

Cache headers

<IfModule mod_headers.c>
  Header unset ETag
    
  <IfModule mod_alias.c>
    # disable browser cache for serviceWorker.js file
    <FilesMatch "^(serviceWorker.js)$">
      Header unset Expires
      Header set Cache-Control "max-age=0"
    </FilesMatch>
    
    <FilesMatch "\.(js|css)$">
      # cache for 24 hours = 86400 seconds
      Header set Cache-Control "max-age=86400, public, no-transform, must-revalidate"
    </FilesMatch>
  </IfModule>
</IfModule>

index.html

...
<body style="overflow: hidden">
    <div id="app"></div>
    <script src="/dist/main.bundle.aae6d2bb162cbee13899.js"></script>
    <script src="/dist/0.bundle.aaa837f16bb646266d99.js"></script>
    <script src="/dist/1.bundle.aa653fe9abbe232be599.js"></script>
    <script src="/dist/2.bundle.aa3096daabb2d428a899.js"></script>
    <script src="/dist/3.bundle.aa1650fc5bb4e1f1ea99.js"></script>
    <script src="/dist/4.bundle.aae80e50cbb06d5e5599.js"></script>
    <script src="/dist/5.bundle.aa1824b9ebb0cb931b99.js"></script>
    <noscript>
        Sorry, this page requires javascript!
     </noscript>
</body>
</html>

Despite all these solutions the app still caches in all tested browsers (FF, Chrome, Safari) and in the PWA. The cache will only refresh after one or more reloads and/or hard reload.

I have also verified that the bundle file hash have changed for updated code between releases.

Example of old file before code update and deploy

5.bundle.aa1824b9ebb0cb931b99.js

Example of new file after code update and deploy

5.bundle.cae6d2bb162cbee138bc.js

The reference in index.html to the bundle file is updated with the new hash, but the browser still tries to fetch the old file - resulting in fatal error "ChunkLoadError: Loading chunk [n.oldHash] failed.".

Am I doing this wrong? Is there any other way to force the browser (and PWA) to refresh all code after a new release?

Kind regards /K


Solution

  • I followed similar principles as mentioned in this post to clear my cache. I just made the request on a setInterval rather than wrapping the app in a clear cache HOC. https://dev.to/ammartinwala52/clear-cache-on-build-for-react-apps-1k8j the article this links to also has some good examples, it is worth looking at both. https://dev.to/flexdinesh/cache-busting-a-react-app-22lk

    Not sure if this is the best approach, but it works for me