Deploy Create-React-App with Cloudfoundry

August 22, 2020 ☼ JSReactCloudfoundry

In this short article I’ll explain how to publish a Single Page Application built with CRA to Cloudfoundry. The following set-up assumes that your Backend is separated from your Frontend and deployed in another container.

Prerequisites

What do we need?

First of all, we need to understand what CRA ouputs when we run the build command (npm run build):

my-react-app/
  build/
    ...
  README.md
  node_modules/
  package.json
  public/
    ...
  src/
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg

What you are interest in deploying is the build folder. It contains all the necessary static resources and the single index.html that is needed to run the app.

How do we deploy it then?

Enters Staticfile Buildpack

Cloudfoundry kindly provides a runtime that support staticfile apps with backends hosted elsewhere. Behind the scene the buildpack provides a NGINX web-server.

The nice thing about this Buildpack is that it’s configured basically to work out of the box with little configuration from our side! Just create a file named Staticfile and locate it in the build directory of your app, Cloud Foundry automatically uses the Staticfile buildpack when you push your app.

For our purpose though, will extend the configuration to make use of NGINX directives to have a better control of caching headers.

Show me the code

location /index.html {
  # A negative value means that the response expires immediately.
  # Nginx automatically sets the `Cache-Control: no-cache` header, if `expires` is negative
  expires -1;
}

location ~*  \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
  # Increases content delivery speed and reduces the size of log files
  access_log off;
  # not needed since we're going to cache the file forever
  etag off;
  add_header Cache-Control "public,max-age=31536000,immutable";
}

The first declaration will prevent the server to cache index.html. This is very important. We don’t want to serve stale content to our users.

The second RegEx defines the caching headers for all the static content.

We use immutable as a value here. It provides the browser with hints as to which resources never change. The major advantages of using immutable directive are:

  1. Better performance, since the browser doesn’t need to check the server to verify whether or not the asset is still valid

  2. Less network bandwidth is consumed for the same above reason.

Attention: in order to be safely use this directive we need to make sure that our assets’ name are being hashed on every build. CRA does it for us every time we run npm run build.

root: build
gzip: on
location_include: includes/*.conf

It describes where to find the files and the custom configuration.

If you want to find out all the possible configuration parameters refers to the docs.

applications:
  - name: my-react-app
    buildpacks:
      - staticfile_buildpack
    instances: 2
    memory: 1G

Your app should be now live and ready to serve your customers.

That’s all folks 🎉

Bonus

You can ad a .cfignore file in your root to speed up the push of your app:

coverage/
reports/
bin/logs/
node_modules/
src/

If you have any suggestions, questions, corrections or if you want to add anything please DM or tweet me: @zanonnicola