Photo by Franck V. on Unsplash

Create-React-App Continuous Integration Config with CircleCI and AWS

Everybody writes code, what is your difference as a pro/company from a junior high school student? Quick response to rapid changes, better organisation, sustainability, security and of course, quality!

Automation has a key role here. Thanks to agile methodology, it brings us tons of tools to automate the processes. There are lots of things to talk about this. But to cut a long story short, I’ll start to talk about this post’s main goal.

This post is about continuous integration of create-react-app application. I’ll create a front-end continuous integration with CircleCI and introduce some tools that will help our flow. This will be a pretty long post, titles of the post can provide you insight about the content:

  1. New CRA application
  2. CircleCI CRA Integration
  3. Static Analysis with ESLint
  4. Cost Analysis with Size-Limit
  5. Vulnerability Analysis with Snyk
  6. End To End Testing with Cypress
  7. Deployment to AWS S3
  8. Code

Let’s start!

New CRA application

Surely the first thing to do is creating a react app using create-react-app. And create a repository on Github(or Bitbucket)

npx create-react-app cra-ci-demo
rm -rf .git
git init
git remote add origin <YOUR REMOTE REPO URL>

After started new app, we removed the original .git folder, inited new git and added our repo-url as remote.

CircleCI CRA Integration

CircleCI is one of CI tools at the market. It has a cloud option and a great pricing strategy for newcomers.

Now you need a config.yml file inside a .circleci folder at the project’s root. Your projects root should be like below.

And config.yml content will be like below.

version: 2.1jobs:
- image: circleci/node:12.9.1-browsers

working_directory: ~/repo
- checkout

- restore_cache:
- v1-dependencies-{{ checksum "package.json" }}
- v1-dependencies-

- run: yarn install

- save_cache:
- node_modules
- ~/.npm
- ~/.cache
key: v1-dependencies-{{ checksum "package.json" }}

- run: yarn test

Ok, let’s look what’s going on here;

  • We are using circleci config version 2.1.
  • In the jobs->build we are giving the config details.
  • For this build, we’ll use circleci/node:12.9.1-browsers image. Because we’ll try to implement an e2e test soon. This image has built-in chromium. You can see the other circleci images here.
  • checkout will checkout the code from your repository.
  • restore_cache will restore the cache if exists
  • run: yarn install will install the packages
  • save_cache will cache node_modules, .npm and .cache directories to speed up following builds.
  • run: yarn test will run the tests

Now, commit and push your code and signup to CircleCI and click Add Project. Choose your repository, select Linux-Node and click Start Building.

Now CircleCI will run your build and if you don’t get an error you’ll see a row like this.

Congratulations, you implemented a CirceCI flow which is doing almost nothing. Now we need to extend it.

Static Analysis with ESLint

Linting is a crucial part of frontend projects freely how great developers your team has. Our CI should catch syntax errors and suspicious patterns.

Create-React-App is coming with ESLint and it’s own rules. No need to install anything. We should only create the configuration. Firstly we’ll create a new script command. Scripts part of our package.json should look like this;

"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.js --max-warnings 5"

We added the lint script. This script will lint our code and throw an error(Exit(1)) if the warning count is equal or more than 5.

It’s time to add lint script to our config.yml

- save_cache:
- node_modules
key: v1-dependencies-{{ checksum "package.json" }}

- run: yarn lint

- run: yarn test

If your build succeeded you will see a new row titled yarn lint at CircleCI build screen like below:

Lint is done, it’s size-limit’s turn.

Cost Analysis with Size-Limit

Size-Limit is a great tool from Andrey Sitnik. It calculates your projects download and execution performance. It’s a unique opportunity not to be surprised at the production environment because of newly added modules.

We need to add the preset-app of size-limit first:

yarn add --dev @size-limit/preset-app

Next, we’ll add a new script.

"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.js --max-warnings 5",
"size": "yarn build && size-limit"

And we’ll add a tiny configuration to package.json.

"size-limit": [
"path": "build/static/**/*.{js,css,svg,woff,woff2,png,ttf,html}"

At this point if you try

yarn size

You’ll see a report like this:

If you want to create a threshold on CI, you can add limit parameter to size-limit configuration. Last part is adding the script to config.yml


- run: yarn lint
- run: yarn size- run: yarn test

Vulnerability Analysis with Snyk

Thus far we have more than 1000 dependencies in the node_modules folder. How do you trust all of these dependencies? How do you know all of them are secure? You can’t unless you use a vulnerability scanner. Snyk is staging now.

If you want to add your CI a vulnerability scan step with Snyk. The easiest way is using CircleCI Snyk Orb

Here are the steps:

  1. First of all login to Snyk dashboard and add project pointing your repository.
  2. Get Snyk API Token from Snyk General Settings. Note it.
  3. At CircleCI project page, create an environment variable named SNYK_TOKEN with this API token you noted.
  4. Add snyk orb just after version definition of config.yml
version: 2.1
snyk: snyk/snyk@0.0.8


5. Add snyk scan step to config.yml

- run: yarn size
- run: yarn test- snyk/scan:
fail-on-issues: false
monitor-on-build: false
severity-threshold: high

That’s all! You added two new rows to your CI build steps.

You can also play with some cool Snyk features, like monitoring, fixing or alerting. But these are not this article’s subject.

End To End Testing with Cypress

You have unit tests and some quality analysis. But hey, I have big news: your end-users don’t care any of them. Sorry.

We need an e2e testing framework to be sure about your end user's happiness. Cypress offers a better and easier solution than Selenium or Pupetteer IMHO.

I’m starting with the dependency installations.

yarn add --dev cypress
yarn add --dev start-server-and-test

We added start-server-and-test for a better boot up strategy. Next, I will add some scripts to package.json.

"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.js --max-warnings 5",
"size": "yarn build && size-limit",
"cypress:run": "cypress run --record --key=${CYPRESS_RECORD_KEY}",
"ci:cypress-run": "start-server-and-test start http://localhost:3000 cypress:run"

Let me explain the last two rows:

  • cypress:run runs cypress client and record the results to cypress dashboard. Bu this script needs a running project. You have to start your project in another terminal window manually. Also, you need to add a CYPRESS_RECORD_KEY environment variable for sending the record of the test.
  • ci:cypress-run starts your project and runs the previous code. Great for CI environments.

Now start cypress client

yarn cypress open

Open Runs tab and set up your project.

When you return to your project folder, you should see cypress folder and cypress.json file

Before writing a simple test. I’m removing example folder under cypress/integration. I don’t want to run any other test. Now create a sample_spec.js to the same path. It looks like below:

My test will be a dummy one. It browses localhost:3000, gets App-header class, finds the element contains ‘Learn React’ text and expect to have href attribute pointing the reactjs URL.

You can create beautiful tests with all browser interactions like click, scroll, type etc…

Finally, add cypress script to CircleCI config.

version: 2.1
snyk: snyk/snyk@0.0.8
cypress: cypress-io/cypress@1.23.0
....- run: yarn test- run: yarn ci:cypress-run- snyk/scan:
fail-on-issues: false
monitor-on-build: false
severity-threshold: high

Note: don’t forget to add CYPRESS_RECORD_KEY to CircleCI environment variables.

After your build succeeded, open Cypress dashboard you will see result, logs, duration and even video of the test. Yep, this is cool! :)

Deployment to AWS S3

We have come a long way so far. Now it’s time to sail into the West. (a tribute to Tolkien)

Here are the steps:

  1. Ensure to have an IAM user with S3 rights. (AmazonS3FullAccess is a way)
  2. Note Access Key ID and Secret Access Key of IAM User
  3. Create an S3 bucket
  4. Go to the bucket Permissions tab and uncheck Block all public access
  5. Go to Access Control List and give List Objects to the Everyone group
  6. Go to the bucket Properties tab and enable Static Web Hosting with index.html
  7. Return to CircleCI dashboard and add these environment variables: Access Key ID as AWS_ACCESS_KEY_ID, Secret Access Key as AWS_SECRET_ACCESS_KEY, region name as AWS_REGION
  8. Add aws-s3 orb to config.yml
version: 2.1
snyk: snyk/snyk@0.0.8
aws-s3: circleci/aws-s3@1.0.11

9. Add a final build and aws-s3/sync step to config.yml

- run: yarn ci:cypress-run
- snyk/scan:
fail-on-issues: false
monitor-on-build: false
severity-threshold: high
- run: yarn build- aws-s3/sync:
from: build
to: 's3://cra-ci-demo/'
arguments: |
--acl public-read \
--cache-control "max-age=86400"
overwrite: true

Commit, push and watch. It’s possible to create staging or dev builds based on different git branches. Workflows should be used in this case.


Here is the source code:

That’s all. Happy coding

Mostly developer, almost traveller, already gamer