Deploy React application to AWS S3 using GitHub Actions

React is lightweight, S3 is cheap, GitHub Actions make deployment easier. Why don’t we try to use them together?

Why?

React became dominant in frontend development and it became first choice library for front-end development.

S3 is actually very cheap.

GitHub Actions abstract away a lot of complexity inside CI/CD workflows and they give us a chance to create easily understandable workflows faster.

Prerequisites

What we will need to make this work:

Let’s get started

1. Create React application

npx create-react-app react-github-actions

2. Create GitHub repostory

gh repo create react-github-actions

NOTE: It will ask you if you want to create local project directory, say yes.

3. Push the changes to repo

cd react-github-actions
git push --set-upstream origin master

4. Set AWS credentials

Get AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

You can find out how to do it here.

export AWS_ACCESS_KEY_ID={value_of_access_key_id}
export AWS_SECRET_ACCESS_KEY={value_of_secret_access_key_id}
export AWS_DEFAULT_REGION=us-east-1

5. Set GitHub environment variables

And while we are here, let’s set these environment variables on GitHub repository too, since we will need them in our workflow.

Go to: https://github.com/{YOUR_USERNAME}/{YOUR_REPOSITORY}/settings/secrets

Enter:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_DEFAULT_REGION
  • Set them to the same values as in previous step.

6. Create S3 bucket

aws s3 mb s3://react-github-actions

7. Create GitHub workflow

In this scenario we would like to do three things on push of every tag to the git repository.

We define three essential steps, which are jobs inside workflow: build, deploy, release.

Create file workflow file:

touch react-github-actions/.github/workflows/react-github-actions-workflow.yml

You can find the whole workflow here. But I will go through more details in the text:

Let’s start with specifying to for it to run on every new tag push:

on:
push:
tags:
- '*'

The first step would be build job which also tests the app and if test fail, then whole workflow will be stopped.

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Clone repository
uses: actions/checkout@v2
- name: Use Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install dependencies
run: npm install
- name: Test
run: npm test
env:
CI: true
- name: Generate build
run: npm run build
# Share artifact inside workflow
- name: Share artifact inside workflow
uses: actions/upload-artifact@v1
with:
name: react-github-actions-build
path: build

Next job is deploy which will basically take actualbuild from previous job and upload it to S3 bucket using aws-cli:

jobs:
build: ...
deploy:
runs-on: ubuntu-latest
# When application is successfully tested and build has been generated
# Then we can start with deployment
needs: build
steps:
# Download previously shared build
- name: Get artifact
uses: actions/download-artifact@v1
with:
name: react-github-actions-build
# Set the credentials from repository settings/secrets
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
# Copy the files from build folder to the S3 bucket
- name: Deploy to S3
run: aws s3 sync . s3://react-github-actions --acl public-read
working-directory: react-github-actions-build

Now we just zip the build and officially release it to the GitHub repository:

jobs:
build: ...
deploy: ...
release:
runs-on: ubuntu-latest
# We specify that deploys needs to
# finish before we create a release
needs: deploy
steps:
# Download previously shared build
- name: Get artifact
uses: actions/download-artifact@v1
with:
name: react-github-actions-build
# Zip the build using external action
- name: Zip build
uses: thedoctor0/zip-release@master
with:
filename: react-github-actions-release-build.zip
path: react-github-actions-build
# Upload as an artifact of the current workflow
- name: Upload build zip artifact
uses: actions/upload-artifact@v1
with:
name: react-github-actions-release-build.zip
path: react-github-actions-release-build.zip
# Make official GitHub release which will trigger
# sending the mail with link for access
- name: Release
uses: ncipollo/release-action@v1
with:
artifacts: react-github-actions-release-build.zip
body: https://react-github-actions-bucket.s3.amazonaws.com/index.html
token: ${{ secrets.GITHUB_TOKEN }} # Available by default

8. Is it working?

Let’s push the new tag and see:

git add .
git commit -m 'Add workflow'
git tag -a v0.0.1 -m 'First version'
git push origin v0.0.1

Now we wait for an email from GitHub with the link to the React application:

9. Conclusion

What we realize from this article is that GitHub Actions are a nice add-on for creating simpler and easier to understand workflows.

GitHub Actions are simple to use and integrate, and they rely on a lot of existing open source software.

The highest selling point is that Actions are provided inside GitHub repositories by default. In the most of the cases, actions will save you a lot of time.

Of course, there is so much more to do here.

We could introduce CloudFront in order to make it available in more regions, add domain via Route53 and many more things, but that’s material for another article.

Ping me on @ljmocic if you have any questions!

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

If you got so far, you probably found something useful. Please consider supporting me :D

Software Engineer