CI pipeline for ReactJS apps using GitHub actions
Tags: cicd, beginners, githubactions, productivity
Published: 2023-06-14 17:31:20

Hey folks,

In this post, we will understand and gain knowledge about "How to create basic CI pipeline for your React App using GitHub Actions?". 

## Prerequisites 
- Basic understanding of Git & GitHub.
- Basic understanding of JSON notation.
- Any react application source code made with your efforts🤓. (You can contribute to others code as well 😉) 

## 🧐 Firstly, what are GitHub Actions and what is CI?
To simply put, these are set of actions that are triggered on Git events like push, pull request and are executed in the sequence mentioned through the workflow file.

CI (Continuous Integration) is the process building and testing the code for every commit made on your chosen branches. It ensures that everything in the code is working fine after the commit is merged just like in your local machine.

## 😯 That's bit too much, now what is the workflow file??
It is the actual file, that is responsible for defining the actions on git events for continuous integration and deployment. You can customize your workflow file to work with any your own personalized CI/CD server deployed on tools like Jenkins, Ansible, Travis CI, etc.

## 😓😢 Didn't have personalized CI/CD server to serve the CI purpose??
Don't worry my friend! GitHub actions comes to rescue. You don't need to have any personalized CI server anymore. When a workflow file is detected by git, it starts working on with it. Identifying that there is no personalized CI server defined in workflow file, GitHub actions starts deploying machines from its own marketplace and begins running the actions mentioned by you.

## Yay!😊 Now that we have got the basic understanding of theory behind our idea. Let's start understanding the workflow file for CI pipeline for react-app.

- Follow through your project structure and make necessary changes or adjustments to your workflow file later. 

- This is my project structure at high-level. Inside the react-app folder, it is like any other react-project like yours.
![Project Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6n6a2tz5h2roj5t83avc.png)

- Always keep your workflows folder like mine, in the root level of the folder. So create a `.github` folder, inside of which create another folder as `workflows`. 

- Inside workflows folder, create a workflow file with any name using `.yml` extension. Add the following code to the workflow file.

```
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node

name: Node.js CI for SplitWise React App

on:
    push:
        branches: ["develop"]
    pull_request:
        branches: ["develop"]

jobs:
    build:
        runs-on: ubuntu-latest

        defaults:
            run:
                working-directory: ./react-app/

        strategy:
            matrix:
                node-version: [14.x, 16.x]

        steps:
            - uses: actions/checkout@v3
            - name: Use Node.js ${{ matrix.node-version }}
              uses: actions/setup-node@v3
              with:
                  node-version: ${{ matrix.node-version }}
                  cache: "npm"
                  cache-dependency-path: "./react-app/package-lock.json"

            - run: |
                  npm i
                  npm run build
                  npm run test

```

## What is Yaml file?? 🫠
Yaml (.yml) file syntax is inspired from JSON notation. It's kind of similar to expanded JSON notation without brackets. The space indentation in yaml file serves the purpose of brackets in JSON file.

## Let's understand the workflow file line by line. 🤔

All the keys in the workflow file are standard keywords for CI pipeline. They are all self-described, but I will try to help you understand in my way.

- **name**: defines the name of the pipeline
- **on**: defines the rules for git events.
- **push/pull_request**: defines the git events.
- **branches**: defines a value or list of branch names or branch name patterns that uses this workflow.
- **jobs**: defines the jobs for pipeline to run on git events.
- **build**: custom defined name for build job.
- **runs-on**: defines a value or list OS machines that are deployed into server instances.
- **defaults**: takes in nested rules or objects, for overriding default values.
- **run**: defines the run task parameters.
- **working-directory**: under run task, we are mentioning the working directory in our folder structure. In general, it will be the root directory.
In my case, I have two variants of the same application, python console app and react web app. I want this workflow to work only for react-app, hence the path `./react-app/`.
- **strategy**: defines the rules for the same job with multiple software versions.
- **matrix**: defines the structure to list the software versions over the same job.
- **node-version**: custom key to list node versions, to be used later in common job steps.
- **steps**: defines the start of steps in the later lines of code. Hyphen syntax is used to index each step under a job.
   - Each step can be named or ignored.
   - Each step can be manually defined like the `run` step or
   - Each step can use existing defined templates defined in the GitHub actions marketplace like in step 2.
   - actions/checkout@v3 is necessary to ensure that the jobs are ran on the selected branches.
   - actions/setup-node@v3 is used to setup the node in each job with different versions from matrix.
- **with**: defines the rules used for defining multiple jobs over the same steps (like for ensuring software compatibility with multiple dependency software versions).
- **node-version**: a pre-defined keyword for defining the node version needed by actions/setup-node@v3 to setup on the run.
We use `${{ variable }}` syntax to stuff values into yaml file. Here, I have used it for picking node-versions from matrix and thereby creating multiple jobs.
- **cache**: defines the cache module. Since it is react-app, it uses `npm` for cache.
- **cache-dependency-path**: it defines the file path for cache and dependency module or package versions. Generally, it is served by package-lock.json or yarn-lock.json file and it will be available in the root directory of the project.
In my case, there is slight change in the location package-lock.json file, so I have updated the proper path for it.
- **run**: under steps, it is predefined key that takes a command to execute in the server (ubuntu) against software image defined in the matrix (node) for the specific job.
   - You can use pipe (|) operator in the first line, to write multiple series of commands to execute on the same the run.
   - If any run command fails, the next series of commands in the order will be prevented from execution.
   - And come on! You know the commands necessary for building a react-app. 👍😉 

## Everything is ready with our CI pipeline, now it's time to check it action. 😎
- With all your changes in your local machine, stage them and make a commit.
- Push the commit to your remote origin repository.
- Head over to GitHub and open your repository. There on the top local nav menu, click on `Actions` tab.
- You should see your workflow file getting used for CI against your commit.

![My GitHub Actions for CI pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rt7k02vikjpx267ff7r3.png)

**PS**: I have been working to fix the errors in my project 🤞. Your project should be doing fine 👍. 

## Final thoughts 😶‍🌫️
I have shared my knowledge to the best on creating a CI pipeline for building jobs for every code commit with basic and important rules. Please, feel free to share your thoughts and your experiences in the comment section. Happy Coding!! 🤗