Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Browser Cache Busting on S3 + Cloudfront

I host a static website on S3 + Cloudfront. To redeploy, I upload static files with

aws s3 sync static

and invalidate the cloudfront cache with

aws cloudfront create-invalidation

What is the recommended way to force browsers to get these new assets after I update them? The problem is that browsers are caching these assets and users are getting old (invalid) versions of scripts, images, and styles.

like image 280
Will Avatar asked Mar 23 '18 19:03

Will


2 Answers

Generally, there are multiple steps you can do to make sure your AWS CloudFront and S3 setup to cache bust upon new deployments.

  • Make sure you invalidate the cache for index.html (If this is cached)
  • You can either have query parameters or new file names for static assets such as JavaScript, CSS & etc.

Using New File Names

<!doctype html>
<html lang="en">
  <head>
     <link href="styles.h2d1f722.css" rel="stylesheet" />
  </head>
  <body>
     <script type="text/javascript" src="scripts.cbe3c974.js"></script>
  </body>
</html>

You can generate new file names using your frontend build tool (e.g Webpack, Gulp & etc.)

Using Query Parameters

<!doctype html>
<html lang="en">
  <head>
     <link href="styles.css?hash=h2d1f722" rel="stylesheet" />
  </head>
  <body>
     <script type="text/javascript" src="scripts.js?hash=cbe3c974"></script>
  </body>
</html>

When setting up Query Parameters, make sure you have enabled it in CloudFront (Otherwise the cached response of the file will be returned).

Note: Comparing these two approaches there are pros and cons of each of them. Having same file name, you are able to version the files using S3 native versioning while having new names, it doesn't make much sense to do it since new deployments add new names for the files. Also having new file names, makes the S3 bucket cluttered unless you remove or move the old file to another bucket.

  • Make sure you have appropriate values Meta tags in the index.html (Cache-Control, Expires, and Pragma Headers).

Using Meta Tags

<!doctype html>
<html lang="en">
  <head>
     <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" />
     <link href="styles.css?hash=h2d1f722" rel="stylesheet" />
  </head>
  <body>
     <script type="text/javascript" src="scripts.js?hash=cbe3c974"></script>
  </body>
</html>

In this example, it instructs not to cache at browser. However, you can setup appropreate values for these.

  • Practice a versioning scheme for static assets, so that even if an older version of the index.html is served to the end user (Cached from the browser), still the web page loads with old assets (JS, CSS & etc.) without any issues.
like image 132
Ashan Avatar answered Sep 28 '22 11:09

Ashan


You cannot force browsers remote if they already hold the cache values, unless manually intervened.

You need to append

script.something.js?buildid=someuniquereference

and make cloudfront not to cache on query string parameters.

You can also include filename.hash.js or filename.hash.html and with index.html / default document, reduce the time of caching with cache control headers.

This way if you make any changes, you can change that number, cache will be busted on the client as well.

But once you sent the cache headers, there is no way you can clean up the client cache on the browsers remotely.

Hope it helps.

like image 43
Kannaiyan Avatar answered Sep 28 '22 13:09

Kannaiyan