Node.js/Express setHeaders for cache control client side

Hello fly community!

Not sure where else to inquire as I’ve exhausted google links and reading up on cache control.

Fly deploys perfectly fine with Github Actions, what I’m having trouble with is the client side caching inconsistency. Every time I deploy a new build with changes to the frontend, the client inevitably has cached an old version of index.html which points to a non-existent .js file, loading a blank page.

Currently I serve a create-react-app build folder from Express/NodeJS via:

app.use(express.static('build', config.STATIC_OPTIONS));

where my options within a config file are:

const STATIC_OPTIONS = {
  etag: false,
  setHeaders: function (response) {
    return response.set('Cache-Control', 'no-cache, must-revalidate');
  }
};

From my understanding, no-cache means that “response must be validated with the origin server before each reuse”… and with a new GET request to the server, the client should get an updated index.html file if the tags point to a new file?

I’ve checked the headers within the browser devtools, along with using Postman to double check, and the cache-controls in the response is indeed as I had set it as above.

I have also tried adding in (apparently not quite useful) meta tags within the index.html:

    <meta http-equiv='Cache-Control' content='no-cache, must-revalidate'>
    <meta http-equiv='expires' content='0'>
    <meta http-equiv='pragma' content='no-cache'>

To which also has not solved the issue.

If I set the Cache-Control to 'no-store', it will finally and always serve the updated index.html with the build, but of course it wouldn’t be very efficient by not allowing client caching at all of the entire build on each request for the application.

Am I just setting my headers completely wrong? I’m sure there’s probably a simple way given how often there is a need to consistently deploy new builds during production. Been slowly feeling demoralized with the blank page on reload unless I hard-refresh, which isn’t feasible if this was “in production”.

Thank you for your time in reading this, I hope someone can educate me on the matter :sweat_smile:

Alright, finally found a solution after 2 days of mulling over this. Just an update for future devs who happen to run into the same problem with create-react-app build served by an Express backend:

Cache-Control header can be set specific to file path, and to specify to never cache the index.html:

app
  .use(express.static('build', {
    index: 'index.html',
    setHeaders: (res, path) => {
      res.set({
        'Cache-Control':
           //never cache index.html, but can cache everything else if static files are unchanged
          (path.includes('index.html'))
            ? 'no-store'
            : 'public, max-age=0'
      });
    }
  }));

:melting_face:

1 Like

iTHANK YOU MY SAVIOR.

Just in case it helps, this Cloudflare documentation on http cache-control is pretty good: https://archive.is/Fvopo