Skip to content

Deploy to Heroku

JP Barbosa edited this page Feb 10, 2017 · 1 revision

Now that we have a great, database-driven app, it's time to deploy it and show it to the world!

We're using the Heroku platform to host it, since the deploy process is very straightforward and effortless.

First of all, we should adapt the back-end server to receive the react-router routes and direct them to index.html where they belong. We'll also use a directory called build as the app root for reasons that will be shown later through this step.

nano server.js
...
const path = require('path');
...
app.use(express.static(path.resolve(__dirname, 'build')));
...
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});

The * route will accept anything that's not the routes already declared and must be the last to be declared in the file, otherwise it will just capture anything and the app will break.

With that little adjustment done, it's time to prep the app for deployment.

Installing Heroku Toolbelt and creating a new app

To install the Heroku Toolbelt, follow the docs on Heroku CLI on how to do it.

Once the toolbelt is installed, try running which heroku on your terminal to see if it's installed correctly.

$ which heroku
/usr/local/bin/heroku

Log in to your Heroku account by running heroku login.

$ heroku login
Enter your Heroku credentials.
Email: ****@example.com
Password (typing will be hidden): *******
Logged in as ****@example.com

Once logged in, go to your app's root dir and run heroku create.

$ heroku create
Creating app... done, ⬢ quiet-badlands-18267
https://quiet-badlands-18267.herokuapp.com/ | https://git.heroku.com/quiet-badlands-18267.git
Tidbit

If you supply an app name to the create command, i.e. heroku create app-name, Heroku will create an app with that name and its address will be app-name.herokuapp.com.

Installing the mLab add-on

Now we have a new Heroku app that's already online, but doesn't have anything running yet. Before we deploy our app, though, we need to install an add-on called mLab that's going to host our MongoDB database.

$ heroku addons:create mongolab
Creating mongolab on ⬢ quiet-badlands-18267... free
Welcome to mLab.  Your new subscription is being created and will be available shortly.  Please consult the mLab Add-on Admin UI to check on its progress.
Created mongolab-corrugated-31009 as MONGODB_URI
Use heroku addons:docs mongolab to view documentation

Notice that MONGODB_URI is already set for our app.

Deploying the app

With that done, we now need to add a script to package.json called heroku-postbuild that Heroku runs after installing and building all dependencies to your app. heroku-postbuild will run the script that will create a production React App build that won't rely on react-scripts to run, hence the need to adapt server.js to serve the app itself, too.

nano package.json
...
"scripts": {
...
    "heroku-postbuild": "react-scripts build"
}
...

Because of having to run react-scripts build during deployment, we will also need to move react-scripts to production dependencies from devDependencies.

The final package.json should look like this:

{
  "name": "react-apz",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "concurrently": "^3.1.0",
    "dotenv": "^4.0.0"
  },
  "dependencies": {
    "body-parser": "^1.16.0",
    "express": "^4.14.1",
    "mongodb": "^2.2.22",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-redux": "^5.0.2",
    "react-router-dom": "next",
    "react-scripts": "0.8.5",
    "redux": "^3.6.0",
    "redux-thunk": "^2.2.0",
    "uuid": "^3.0.1"
  },
  "scripts": {
    "start": "concurrently \"react-scripts start\" \"node server.js\"",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "heroku-postbuild": "react-scripts build"
  },
  "proxy": "http://localhost:8080"
}
Heroku issues with Yarn

As of the last time this guide was updated (02/10/2017), issues have arisen with using yarn to build the app's dependencies. Heroku automatically uses yarn upon detecting a yarn.lock file in your source code. However, inconsistencies have been reported lately and it's highly likely that your app may fail to build when deploying to Heroku, so, in the meantime, we will add yarn.lock to a .slugignore file, so Heroku ignores yarn.lock and proceeds to install the app's dependencies via npm.

echo "yarn.lock" >> .slugignore
git add .
git commit -m "Ignore yarn.lock when deploying to production"

Lastly, we need to tell Heroku what it should run to serve the app, namely node server.js. To do that, we will create a Procfile that will describe the type of process to run (whether it's a web server, a queue worker etc.) and what the process will run (e.g. the command line).

nano Procfile
web: node server.js

Heroku apps need at least 1 web-type process (or, to use the correct word, dyno) to be able to serve apps through HTTP(S). In this case, we're telling it to serve our app to the web by running node server.js.

Now, that we're good to go, commit all of your changes to your Git repo (or, if you haven't started a Git repo yet, run git init then heroku git:remote, then commit your changes).

After committing all of the changes to your app, run git push heroku master.

git add .
git commit -m "Add Procfile"
$ git push heroku master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 343 bytes | 0 bytes/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
.
.
.
remote: -----> Build succeeded!
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote: 
remote: -----> Compressing...
remote:        Done: 30.9M
remote: -----> Launching...
remote:        Released v7
remote:        https://quiet-badlands-18267.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/quiet-badlands-18267.git
   7957415..f903b78  master -> master

The app has now been deployed. You can open it by accessing the URL that was generated by Heroku when you created the app or by running heroku open at the app's root dir.

Here's the app that was created with this guide.

Any issues and questions will be answered at the Issues tab.

Clone this wiki locally