August 22, 2020 ☼ JS ☼ React ☼ Cloudfoundry
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.
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?
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
.
nginx
. Inside it create another folder called conf
and another one called includes
. The final path will result in my-react-app/nginx/conf/includes
expires.conf
. Here will place our custom NGINX configuration: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:
Better performance, since the browser doesn’t need to check the server to verify whether or not the asset is still valid
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
.
Staticfile
in the root directory: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.
manifest.yml
in the root directory:applications:
- name: my-react-app
buildpacks:
- staticfile_buildpack
instances: 2
memory: 1G
cf push -f manifest.yml
Your app should be now live and ready to serve your customers.
That’s all folks 🎉
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