Hacking a quick closed-source react static site in aws s3 and cloudfront, with a lambda helper
Tags: react, cloudfront, staticdeploy
Published: 2022-11-01 03:05:48

We all know about deploying a static react build to an aws s3 bucket.  We can build a react site, e.g. `npm run build` and get an output directory, which we can then serve as a static site, `npx serve ./build` for example.

What is the fasted robust site we can hack together easily ourselves, before we go to third-party services like vercel, netlify, and surge.sh (for instance if you are working for a company that does not want to use out-of-aws third-parties for infrastructure) ? A bucket+cloudfront site is a good option.  I have been running nigh unbreakdable cloudfront sites that have been up for years without complaint and almost zero maintenance. One caveat is that keeping the caching settings and invalidations correct initially is tricky, cloudfront caches at the edge really really well, so we might want to automate invalidation of the / root for ourselves.  

This is where we can have a little fun by using a lambda to automatically trigger on changes to the bucket assets, leaving us with a dead-simple, copy-and-paste - from local folder to bucket - deploy process.


So the first step step is to create a bucket & upload the files to it e.g. `aws s3 sync ./build s3://your-bucket-name`, and then we want a robust and wont-cost-much site DNS, which we can do relatively fast using cloudfront:

1. Creating a cloudfront distribution

- Set the error pages of the cloudfront distribution to point error 404 at /index.html, error 403 at /index.html, so that the react app can route all urls that don't have static assets at them to the main index page.  Set the path at / to have a caching policy of no-cache, must-revalidate, so that people hitting the site will always get a fresh / root result, but we can more aggressively cache other assets because they will get invalidated when we push up.

2. Creating a lambda watcher to invalidate on bucket changes: https://gist.github.com/supinf/e66fd36f9228a8701706

3. Trigger the lambda on bucket changes.
S3 is one of the standard triggers for a lambda function, so you can set S3 changes to trigger the lambda invocation.

![Add AWS lambda trigger](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkbb88ft5mjqeryj8a7x.png)


![Set up your bucket changes to trigger the lambda](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64dbelrlzm7sbkdp323q.png)


s3 -> lambda -> cloudfront

4. In the first stage of development, you may want to wrap the cloudfront distribution behind a WAF (or WAF2, whatever) so you can control who has access to it while you are doing rapid development.  If you don't care who sees or hits the site, skip the WAF, with cloudfront I find you'll rarely need it, your site will be so stable.

## Deploy via CI
Because the infrastructure itself will handle the cache invalidation, your CI can simply be responsible for building the assets.  In the beginning this could be as simple as having an index.html with hello world in it or you could skip right to react and `npm run build` and a github action that runs `cp ./src/* ./build` and then `aws s3 sync ./build  s3://your-bucket-name-here/`.

(You will have to add an aws token secret to your github secrets to allow github action to upload to the bucket)