Skip to content

raoulus/react-to-go

Repository files navigation

🌱 Seed project for React and webpack

CI codecov Last commit Dependency Tracker

Clone this repository and start coding your React app right away. This project tries to give you the best setup and has only really needed dependencies installed. So no worries about configuration, it's all done!

Continuous integration and continuous deployments are configured as github workflow. The CD pipeline compiles and deploys the React app to an AWS S3 bucket triggered on every commit and merge to master.

Features

  • Everything builds on top of latest React and webpack
  • Local development with hot reloading using webpack dev server
  • Linting and code formatting on the fly with ESLint and prettier
  • Pre-configured test environment for component and snapshot tests using Jest
  • Component styling with Less
  • Docker to go! Build a production ready image including Nginx
  • Continuous integration and automatic deployment to AWS S3 with Github actions

Demo
https://d2lk6w0egm4dxt.cloudfront.net/

Table of contents

Getting started

# clone repo
git clone [email protected]:raoulus/react-to-go.git

# install dependencies
npm i

# build production bundle in /public
npm run build

# start webpack dev server with hot reloading
# visit http://localhost:9000
npm run dev

# start express server
npm start

Linting and formatting

This project uses prettier for code formatting in conjunction with ESLint for code linting and fixing.

npm run lint

When using Visual Studio Code the workspace will be automatically configured by .vscode/settings.json.

settings.json

{
  "[javascript]": {
    "editor.formatOnSave": false
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll.stylelint": true,
    "source.fixAll.tslint": true
  },
  "editor.formatOnSave": true,
  "eslint.enable": true,
  "eslint.validate": ["javascriptreact"],
  "javascript.format.enable": false,
  "javascript.validate.enable": false
}

Testing

This project uses Jest and supports Unit (DOM) Testing as well as Snapshot Testing.

Base Dependencies

  • jest
  • babel-jest
  • @babel/preset-env
  • @babel/preset-react
  • eslint-plugin-jest
# run all tests with jest
npm test

# run all tests in watch mode
npm test:watch

Snapshot testing

Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly. https://jestjs.io/docs/en/snapshot-testing

Dependencies

Snapshots are taken and compared with the previous version every time when the tests are executed.

Here's a step by step guide how to create and update snapshot tests.

  1. Write a new snapshot test, e.g. /components/Footer/__tests__/Footer.spec.js
import React from 'react'
import Footer from '../index.jsx'
import renderer from 'react-test-renderer'
describe('<Footer /> ', () => {
  test('matches snapshot', () => {
    const component = renderer.create(<Footer />)
    let tree = component.toJSON()
    expect(tree).toMatchInlineSnapshot()
  })
})
  1. Run initial test (npm test) to replace .toMatchInlineSnapshot() with the actual content
test('matches snapshot', () => {
    const component = renderer.create(<Footer />)
    let tree = component.toJSON()
    expect(tree).toMatchInlineSnapshot(`
      <div>
        <p>
          <i
            className="fab fa-github"
          />

          <a
            href="https://github.com/raoulus/react-to-go/"
          >
            react-to-go (v
            )
          </a>
        </p>
      </div>
    `)
  })
})

In addition to the actual test the snapshot content must be maintained separately. Meaning every time the content of a component changes then the snapshot needs to be updated as well.

  1. Change content
  2. Run tests again npm test
  3. Snapshot tests will fail and needs to be updated with npm test -- --updateSnapshot
Snapshot Summary
 › 2 snapshots failed from 1 test suite. Inspect your code changes or run `npm test -- -u` to update them.
  1. Update snapshot npm test -- -u
  2. Commit changes

Unit (DOM) Testing

This projects follows the recommendation from Jest to use react-testing-library for Unit Testing also known as DOM Testing.

The React Testing Library is a very light-weight solution for testing React components. It provides light utility functions on top of react-dom and react-dom/test-utils, in a way that encourages better testing practices.
https://testing-library.com/docs/react-testing-library/intro

Dependencies

Notes

  • Jest will set process.env.NODE_ENV to 'test' if it's not set to something else
  • Styles (less|css) are mocked, see __mocks__/style.mock.js

Docker build with Nginx

There's a npm command to build docker image using Nginx.

# build image with tag react-to-go:1.0.0
npm run build:docker

# start image
docker run --name react-to-go --rm -p 3000:80 react-to-go:1.0.0

# go to http://localhost:3000

Github workflow with AWS S3

You find the working github workflow under .github/workflows/s3-upload.yml. This workflow contains two jobs namely build and deploy.

build
The job runs npm run build and outputs static assets under /public. To have a clean deployment this folder is saved as artifact for the next job.

deploy
The AWS credentials needs to be configured in order to use AWS CLI (aws sync) to recursively copy new and updated files to an S3 bucket.

Following secrets have to be created in github (repository -> settings -> secrets)

AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=xxx
AWS_REGION=eu-central-1
AWS_S3_BUCKET=react-to-go

AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY can be found in AWS under IAM -> Users -> security credentials.

AWS S3 IAM policy

The access rights for the API user should be restricted for security reasons. Create an IAM policy with the following configuration. This policy can then be attached to a group to which a user belongs.

These permissions are needed to perform aws sync

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:ListBucket",
        "s3:DeleteObject",
        "s3:GetBucketLocation"
      ],
      "Resource": ["arn:aws:s3:::react-to-go", "arn:aws:s3:::react-to-go/*"]
    }
  ]
}