Cristian Rojas
Cristian Rojas

Reputation: 2852

Browser ignoring cache headers and looking for old CSS and JavaScript files after React application deployment

I've created a React application with create-react-app, as you may know there's a npm run build command which exports everything you need for deployment inside of the build folder.

It basically contains an index.html file with all the required assets (images, compressed JavaScript and css files plus some others)

When deploying, I've setup a DigitalOcean droplet with Ubuntu 16 where I installed Express.js in order to setup a server to handle requests, it looks like this:

const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/*', function (req, res) {
  res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

app.listen(process.env.PORT || 8080);

I keep that server running using pm2 with this command: pm2 start server.js

I've installed Nginx to be a proxy with this config (please note Cache-Control, Pragma and Expires headers I'm sending in every response):

upstream react_dev {
  server 127.0.0.1:8080;
  keepalive 64;
}

server {
  server_name                 dev.24mm.co;
  charset                     utf-8;

  proxy_set_header            Host             $host;
  proxy_set_header            X-Real-IP        $remote_addr;
  proxy_set_header            X-Forwarded-For  $proxy_add_x_forwarded_for;

  client_max_body_size        40m;
  client_body_buffer_size     128k;

  proxy_connect_timeout       90;
  proxy_send_timeout          90;
  proxy_read_timeout          90;

  proxy_buffer_size           4k;
  proxy_buffers               4 32k;
  proxy_busy_buffers_size     64k;
  proxy_temp_file_write_size  64k;

  location / {
    proxy_set_header          X-Prerender-Token     [my-prerender.io-token];
    proxy_set_header          X-Forwarded-For       $proxy_add_x_forwarded_for;
    proxy_set_header          Host                  $http_host;
    proxy_set_header          X-NginX-Proxy         true;
    proxy_http_version        1.1;
    proxy_set_header          Upgrade               $http_upgrade;
    proxy_set_header          Connection            "upgrade";
    proxy_max_temp_file_size  0;
    proxy_redirect            off;
    proxy_read_timeout        240s;

    set $prerender 0;
    if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
      set $prerender 1;
    }
    if ($args ~ "_escaped_fragment_") {
      set $prerender 1;
    }
    if ($http_user_agent ~ "Prerender") {
      set $prerender 0;
    }
    if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
      set $prerender 0;
    }

    #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
    resolver 8.8.8.8;

    if ($prerender = 1) {
      #setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing
      set $prerender "service.prerender.io";
      rewrite .* /$scheme://$host$request_uri? break;
      proxy_pass http://$prerender;
    }
    #if (!-f $request_filename) {
    if ($prerender = 0) {
      add_header    Cache-Control   "no-cache, no-store, must-revalidate";
      add_header    Pragma          "no-cache";
      add_header    Expires         0;
      proxy_pass    http://react_dev;
      break;
    }
  }

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_min_length 256;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  listen 443 ssl; # managed by Certbot
  ssl_certificate /etc/letsencrypt/live/dev.24mm.co/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/dev.24mm.co/privkey.pem; # managed by Certbot
  include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
  if ($host = dev.24mm.co) {
    return 301 https://$host$request_uri;
  } # managed by Certbot

  listen 80 default_server;
  server_name dev.24mm.co;
  return 404; # managed by Certbot
}

No matter what I do, every time I deploy my project (i.e. I run npm run build) the browser is looking for the old JavaScript and CSS files, because it has a cached version of the main index.html document. That's of course causing a very bad user experience because all users are seeing a blank page after each deploy.

I'm wondering how to tell the browser never to cache the index.html file.

Upvotes: 1

Views: 822

Answers (1)

Tholle
Tholle

Reputation: 112787

If the browser is not honoring the cache headers, it's usually a registered service worker that gets old assets.

If you have used the service worker in an older version of your app and you don't want to use it anymore, you must explicitly unregister it.

import { unregister } from './registerServiceWorker';

unregister();

Upvotes: 2

Related Questions