3

So, I have a React app hosted on a AWS S3 bucket (It also has a CloudFront distribution before it). Using a GitHub Actions workflow, I deploy my build output on S3 with aws-cli s3 sync command:

aws s3 sync build s3://mybucket --delete --acl public-read

Now, I want to perform static file caching with the denoted starting configuration in the CreateReactApp docs:

  • Cache-Control: max-age=31536000 for build/static assets,
  • Cache-Control: no-cache for everything else (to ensure the browser will always check for an updated index.html file)

Question

How can I achieve applying such conditional configuration on S3 objects based on the file/folder paths?

What I thought/tried so far

  • First I thought it could be done with a setting on the S3 bucket. But after some searching, now, my understanding is that there is no such setting on the bucket itself (at least, answers to this post propose none).
  • Then, I headed to --cache-control flag of aws cli s3 sync docs, but not did I find a direct, one-liner way of applying different cache controls.
vahdet
  • 6,357
  • 9
  • 51
  • 106

2 Answers2

7

Here’s what I use:

aws s3 sync build s3://bucket \
  --metadata-directive REPLACE \
  --cache-control max-age=86400 \
  --exclude index.html --exclude 'static/*' \
  --delete
aws s3 sync build/static s3://bucket/static \
  --metadata-directive REPLACE \
  --cache-control max-age=31536000,immutable \
  --size-only
aws s3 cp build/index.html s3://bucket \
  --metadata-directive REPLACE \
  --cache-control no-cache

Thus the public folder and misc other files are served with instruction to cache for 24 hours, index.html is served with instruction to never cache and the static folder is served with instruction to cache a year and with the immutable flag which supposedly can be a real boon for reloads [1].

Additionally we do not prune the static folder of old assets which means any browser out there that insists on using a stale build will still get those files. Which seems probably the correct choice rather than 404ing and being broken.

CloudFront will use these headers for its own cache and send them out to the browser.

[1] https://hacks.mozilla.org/2017/01/using-immutable-caching-to-speed-up-the-web/

mxcl
  • 26,392
  • 12
  • 99
  • 98
1

This can be done very simply with no configuration on the S3 side, as you're using CloudFront first this would be controlled in the behaviours.

You can define multiple behaviours which are matched based on path patterns. In CloudFront this would display as if you have multiple origins but both could go to the same S3 bucket.

You would have a path pattern of build/static for which you set the caching max age for all objects. Then for the default behaviour you would disable caching of objects.

This article has a basic demonstration for setting it up.

Chris Williams
  • 32,215
  • 4
  • 30
  • 68
  • Funny I skipped CloudFront for a deeper solution as its TTL can be [overridden](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-cachebehavior.html#cfn-cloudfront-distribution-cachebehavior-maxttl) by the resources. However, as you suggest, it may end up being the most proper solution. Gonna try and appreciate further. – vahdet Aug 02 '20 at 12:40
  • Sure, I just think might end up being the simplest solution :) – Chris Williams Aug 02 '20 at 12:41
  • Now, I applied CloudFront TTLs, and a PWA update on it: [Lighthouse scoring](https://developers.google.com/web/ilt/pwa/lighthouse-pwa-analysis-tool) still suggests the static content to be cached: Apparently, CloudFront does not add Cache-Control headers even if applies caching. Anyways, I don't know if Lighthouse or CloudFront to face the issue. – vahdet Aug 03 '20 at 11:40
  • So the objects being cached are not returning cache headers? – Chris Williams Aug 03 '20 at 11:51
  • Apparently so. I have a cache behavior added for `static/*` and fetching an object from `static` folder, does not respond with a `Cache-Control` header. But, instead, it is conveyed with rather a custom header like `x-cache: Hit from cloudfront`. This post also ends up with the idea of CF not setting `Cache-Control` header: https://stackoverflow.com/q/56187791/4636715 – vahdet Aug 03 '20 at 12:34