Building a static site with a web framework instead of a static site generator using Wget, AWS S3 CLI & CircleCI

There are an overwhelming amount of static site generators out there. Over 400 according to this site. What if your requirements don’t require a dynamic server but you still want to use a mature web application framework your familiar with and trust such as Express or Rails. And what if there is potential the site will need to be dynamic in the future and you don’t want to have to migrate your codebase come that point.

You could create a small instance of your app on Heroku or EC2 and not worry about it’s load because of the CDN. But you still have to worry about it’s health and you will pay more in hosting. Also it will unnecessarily regenerate the same response once the cache expires on the CDN’s edge servers. Hosting a static site with a cloud storage service such as S3 is easy, cheap and you know if it works once it will pretty much work for ever.

I re-built and re-hosted GridClub, my work is in production now. It’s a cross-curricular educational games site for kids. I’ve taken the site and rebuilt it in Rails, React and SCSS. I have no database but have my controllers read data out of a single YAML file. For React I use react-rails and have the prerender option set to improve page load time and SEO.

Basically what happens is when I commit to master, CircleCI runs a shell script. It precompiles the Rails assets, spins up the Rails server, Wget crawls it’s pages and fetches the HTML, then it deploys the HTML/asset files to my staging S3 bucket using S3 CLI. I kinda think about Wget’s role as generating a one time response for every URL, and then having S3 return that response for all future production requests to my CDN CloudFront.

Furthermore when I want to deploy to production, I use a Slack Command that triggers a AWS Lambda JavaScript function which in turn triggers a Parameterized CircleCI build. This build has an environment variable set which causes it to run a different shell script which simply syncs my staging bucket to the production bucket. I wanted to go direct from the Slack Command to the CircleCI REST API but it didn’t allow me to set the required JSON body in it’s POST request, I had to go via Lambda.

Here is my in-production script that deploys a static Rails app to an S3 bucket:

Here is my circle.yml file which installs the dependencies and decides which script to run (note for AWS CLI authentication you can put your AWS credentials in the CircleCI Project Settings > AWS Keys):

And finally here is the script that deploys the staging bucket to a production bucket:

So far I’m pretty happy how this has all worked out but I would be interested to hear what other people have done or think. I know you can do some very cool stuff with Webpack for example, and while this is a Rails app I am more Node heavy these days.

Principal Software Engineer based in Sydney

Love podcasts or audiobooks? Learn on the go with our new app.