Image for post
Image for post
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

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.

Image for post
Image for post

And config.yml content will be like below.

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

working_directory: ~/repo
steps:
- checkout

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

- run: yarn install

- save_cache:
paths:
- 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.

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.

Image for post
Image for post

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:
paths:
- 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:

Image for post
Image for post

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:

Image for post
Image for post

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.
version: 2.1
orbs:
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.

Image for post
Image for post

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.

Image for post
Image for post

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.

Now start cypress client

yarn cypress open

Open Runs tab and set up your project.

Image for post
Image for post

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:

Image for post
Image for post

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
orbs:
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)
version: 2.1
orbs:
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.


Code

Here is the source code: https://github.com/eferhatg/cra-ci-demo

That’s all. Happy coding

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store