Continuously deploy a React App to GitLab Pages

If you're looking for a simple way to deploy a CRA app everytime you push new changes, Gitlab Pages can be a great way to do this.

By the end of this article you'll learn how to:

  • setup a GitLab CI pipeline to build the app on every new commit
  • deploy the app to GitLab Pages on every commit to master, automatically

This walkthrough assumes you're using Gitlab to host your repository.

Step 1: Setup the CI pipeline to build the project

What we want is to run yarn build after every commit and to save the contents of the build folder as a GitLab artifact that we can later use.

If you haven't already, create a .gitlab-ci.yml file in the root of your project:

stages:
  - build

build:
  image: node:latest    # Run the job in a `node` docker image
  stage: build
  script:
    - yarn install      # Run `yarn install` and `yarn build`
    - yarn build
  artifacts:
    paths:
      - build/          # Save the build result as an artfact

After pushing your changes, you should already see the pipeline running under  the "CI / CD >> Pipelines" menu.

Step 2: Configure the React app to be served from a subfolder

By default, CRA apps expect the app will be served from the root of a server.

However, in GitLab Pages the app will be served from a subfolder (which represents the project name), and this will cause the React app to break and show the dreaded white page.

The fix is to customize the base path of the React app. There are two ways to configure this, depending on whether you use routing or not (or to be more specific: "if you are using the HTML5 pushState history API or using client-side routing").

If you don't use routes

The easiest way to set this up if you don't use routes is to set the homepage attribute in your package.json to the current folder - . (see official docs).

If you use routing

Then you will need to hardcode the full URL. I recommend configuring the URL by passing in an environment variable at build time, not to pollute your package.json with paths.

First, you will need to figure out the URL of your Gitlab Pages site.
You can find it in the sidebar menu, under "Settings >> Pages".

For example, for my example app, the project URL is https://gitlab.com/jsramblings/coffee-corner and the corresponding Gitlab Pages URL is https://jsramblings.gitlab.io/coffee-corner/.

To pass the URL as an environment variable, we can pass the extra variables key to the build job:

stages:
  - build

build:
  image: node:latest    
  stage: build
  variables: 
    # Replace this with your site URL
    PUBLIC_URL: https://jsramblings.gitlab.io/coffee-corner/  
  script:
    - yarn install      
    - yarn build
  artifacts:
    paths:
      - build/          

Step 3: Setup the GitLab Pages deploy

In order to have the site deployed automatically on every change to the code, we will add a new job to the CI pipeline.

Gitlab Pages expects two things from the deploy job:

  • it must be named pages
  • it must publish its artifacts under a folder named public
# Stages run sequentially, so we add a new `deploy` stage 
# after the `build` one
stages:
  - build
  - deploy

build:
  ... # Same as before
  
pages:
  image: alpine:latest
  stage: deploy
  variables:
    GIT_STRATEGY: none        # Do not clone git repo
  script:
    # Rename the CRA `build` folder to `public`
    - mv build public         
  artifacts:
    paths:
      - public

That's it! Pushing your changes should already start deployting the app.

You'll see the two jobs - build and pages- in the Pipeline view, plus an extra pages:deploy job that confirms the site was published.

I hope you found this walkthrough useful, let me know in the comments below if you have any questions 🙏