Cache busting with CRA React

74,384

Solution 1

EDIT: create-react-app v2 now have the service worker disabled by default

This answer only apply for CRA v1

This is probably because of your web worker.

If you look into your index.js file you can see

registerServiceWorker();

Never wondered what it did? If we take a look at the file it got imported from we can see

// 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.

// To learn more about the benefits of this model, read {URL}
// This link also includes instructions on opting out of this behavior.

If you want to delete the web worker, don't just delete the line. Import unregister and call it in your file instead of the register.

import { unregister } from './registerServiceWorker';

and then call

unregister()

P.S. When you unregister, it will take at least one refresh to make it work

Solution 2

I had the same issue when I use create-react-app ( and deploy to heroku). It keeps showing the old version of my app 😡.

I found the problem seems to be on the browser side, it caches my old index.html with its outdated js bundle

You may want to add the following to your server side response header

"Cache-Control": "no-store, no-cache"

or if you are also using heroku create-react-app-buildpack, update the static.json file

"headers": { 
    "/**": { 
        "Cache-Control": "no-store, no-cache" 
    } 
}

I think in this way you can still keep that poor service worker 😂, and the latest content will be shown on the N+1 load (second refresh)

Hope this helps...

Solution 3

As mentioned by some of the previous answers here, both the service worker and the (lack of) cache headers can conspire against you when it comes to seeing old versions of your React app.

The React docs state the following when it comes to caching:

Using Cache-Control: max-age=31536000 for your build/static assets, and Cache-Control: no-cache for everything else is a safe and effective starting point that ensures your user's browser will always check for an updated index.html file, and will cache all of the build/static files for one year. Note that you can use the one year expiration on build/static safely because the file contents hash is embedded into the filename.

As mentioned by @squarism, older versions of create-react-app defaulted to opt-out of service worker registration, while newer versions are opt-in. You can read more about that in the official docs. It's quite a straightforward process to match you configuration to the latest template if you started with an older version of create-react-app and you want to switch to the new behaviour.

Related questions:

Solution 4

It appears that they changed from opt-out to opt-in with regards to the service worker. Here's the commit that changed the README and it has examples similar to Kerry G's answer:

https://github.com/facebook/create-react-app/commit/1b2813144b3b0e731d8f404a8169e6fa5916dde4#diff-4e6ec56f74ee42069aac401a4fe448ad

Solution 5

If your problem is with resources statically referenced in index.html, such as .css files or additional .js files (e.g. configuration files), you can declare a React environment variable, assign a unique value to it and reference it in your index.html file.

In your build script (bash):

REACT_APP_CACHE_BUST={e.g. build number from a CI tool} npm run build

In your index.html:

<link rel="stylesheet" href="%PUBLIC_URL%/index.css?cachebust=%REACT_APP_CACHE_BUST%" />

The variable name has to start with REACT_APP_. More about environment variables in React: https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables.

Share:
74,384
Alfrex92
Author by

Alfrex92

Front End Developer in Japan. Anime Tourism: https://mipon.org/

Updated on July 08, 2022

Comments

  • Alfrex92
    Alfrex92 almost 2 years

    When I updated my site, run npm run build and upload the new files to the server I am still looking the old version of my site.

    Without React, I can see the new version of my site with cache-busting. I do this:

    Previous file

    <link rel="stylesheet" href="/css/styles.css">
    

    New file

    <link rel="stylesheet" href="/css/styles.css?abcde">
    

    How can I do something like this or to achieve cache busting with create react app?

    There are many threads in the GitHub of create react app about this but no one has a proper/simple answer.

  • Alfrex92
    Alfrex92 about 6 years
    "it will take at least one refresh to make it work" you mean that after second refresh the user will be able to see the new content?
  • Kerry Gougeon
    Kerry Gougeon about 6 years
    @Alfrex92 yes it should.
  • Alfrex92
    Alfrex92 about 6 years
    is there a different solution? where the user only needs to refresh once.
  • Alfrex92
    Alfrex92 about 6 years
    is not working and I am having this error "service-worker.js:1 Uncaught (in promise) Error: Request for serverlessapps.info/static/js/main.496224d6.js returned a response with status 403 at service-worker.js:1" I updated my source code in Github.
  • Kerry Gougeon
    Kerry Gougeon about 6 years
    @Alfrex92 you haven’t deleted the line registerServiceWorker() from index, you need to delete it, sorry if it wasn’t clear.
  • AnApprentice
    AnApprentice almost 6 years
    Do you really want to no-cache for everything? It's just the html file that is the culprit right?
  • Dan
    Dan almost 6 years
    Is this solution desirable? What if you want to keep the service worker continue to cache except when you have submitted updated code?
  • Nick G.
    Nick G. over 5 years
    @Dan Then you need to configure your service worker with versioning and delete the old cache when the version has been bumped up... but thanks Kerry Gougeaon for that quick temp workaround.
  • Ahmad Maleki
    Ahmad Maleki over 5 years
    Can I just remove the registerServiceWorker(); line and the registerServiceWorker.js file?
  • Kerry Gougeon
    Kerry Gougeon over 5 years
    @AhmadMaleki Yes, it's a fine solution if your project isn't deployed, however if your website is already online and someone had the service worker working; it won't get unregistered by simply removing those line.
  • Andy
    Andy over 5 years
    how about importing isLocalhost, registerServiceWorker and unregister then doing an if statement to check if is localhost, registerServiceWorker else unregister
  • Nick G.
    Nick G. about 5 years
    @crstamps2 There might be better answers if you search for them. I turn off/unregister sw while I'm coding. Then once I'm done coding I turn back on/register sw. Use the activate event to delete the old version cache. Then add this snippet to your sw.js where CACHE_VERSION is a string that you update manually when you're done coding (i.e CACHE_VERSION = "1.0.1"):
  • Nick G.
    Nick G. about 5 years
    @crstamps2 self.addEventListener('activate', function (event) { // delete all entries from earlier cache event.waitUntil( caches.keys() .then(function (keys) { return Promise.all(keys.filter(function (key) { return key !== CACHE_VERSION; }).map(function (key) { return caches.delete(key); }) ); }) ); });
  • ohsully
    ohsully almost 5 years
    Thanks for being so thorough here, this is the best answer for my scenario. In case anyone else is trying to ensure that Cloudfront always delivers the most-updated app from S3, it looks like the answer is to configure Cache-Control: max-age=0 on the index.html object in the website bucket.
  • A.com
    A.com almost 5 years
    @bszom how do you set a Cache-Control: no-cache for build/static vs index.html. Is there a property on the meta tag for this?
  • maltem-za
    maltem-za almost 5 years
    @A.com Cache-Control is a HTTP response header and is not related to meta tags. How you configure this depends on how you are serving/hosting your app.
  • Muhammad Usama Mashkoor
    Muhammad Usama Mashkoor over 4 years
    What about our javascript code and the HTML code because they both are not being added whenever I upload my new code.?
  • Harsh Makadia
    Harsh Makadia over 4 years
    Check this article if you want to manage the caching burst on your own - dev.to/flexdinesh/cache-busting-a-react-app-22lk
  • Michal Ciesielski
    Michal Ciesielski over 4 years
    Sorry for the late reply. I think the javascript situation depends on your build process. We use create-react-app (the package.json -> scripts -> build entry is 'react-scripts build'). The build process generates the javascript files and the names of the files include a hash of the file contents. So generally, no extra cache busting for js files is required, I think. If your index html file is being cached, then the problem could be in cache control of the web server.
  • Muhammad Usama Mashkoor
    Muhammad Usama Mashkoor over 4 years
    Thanks, Michal for your reply. Michal, can you please help me how can I handle the cache control of the web server because my react app is on seperate server and Express.js (Node.js) Server is on different server.
  • Michal Ciesielski
    Michal Ciesielski over 4 years
    If I understand your setup correctly, your problem may be with the React app web server. Cache is usually controlled by adding a set of response headers that tell your browser and proxy servers how to cache this website. See this for details: stackoverflow.com/questions/49547/….
  • Muhammad Usama Mashkoor
    Muhammad Usama Mashkoor over 4 years
    Thanks for your detailed reply basically whenever I visit my react app after deploying the lastest code then I always see my previous react deployed build code until I manually clear the cache of the browser. That is my main issue.
  • sushildlh
    sushildlh about 4 years
    @KerryGougeon what about this. // unregister() to register() below. Note this comes with some PITFALLS.
  • irzhy
    irzhy over 3 years