Setup Heroku Hosting for Production

In this section, we're going to dive into the configuration changes necessary to really control our bundles in a production scenario. We'll get into:

  • Optimizing bundles for size for Time to First Byte (TTFB)
  • Exporting separate files from our main.js and loading them asynchronously.
  • Server-side rendering for Time to First Paint (TTFP)
  • Loading Fonts and Markdown
  • Code splitting front end and back end code.
  • HTTP2/Caching/CDNs and other futuristic asset considerations.

But first, we need a platform (or 2) to practice on. I use Heroku for most of my node projects. , which is an industry leader in cloud app deployments and runs atop Amazon Web Services.

We're going to start from a particular branch in our repo that kind of skips over the Choose Your Own Adventure section.

git clone https://github.com/lawwantsin/webpack-course.git
cd webpack-course
git checkout heroku
npm install

Setup Heroku

Heroku has a Command Line interface and a GUI. We're going to use the CLI, the Heroku Toolbelt. Please sign up for a Heroku account and download the Toolbelt app for your platform.

Once installed, in your terminal:

heroku login

Follow the prompts to enter your password.

Heroku login

Once complete you need to create a new project from within the project and create a Procfile for it. This is a "process file" which tells Heroku what commands to run on startup.

heroku create
touch Procfile

In Procfile:

web: npm run prod

In package.json define a new script shortcut:

"prod": "NODE_ENV=production node src/server/main.js"

We're explicitly setting the environment before the command, even though Heroku defines it anyway. Run heroku config to see the NODE_ENV=production setting.

We do this so we can run heroku locally in preparation for the push to prod.

In src/server/express.js we see that express.js is already setup for production, by wrapping much of the DevServer middleware in an if statement. Everything works except the Server's Port. Heroku sets this in a PORT environment variable, so if this is set, we'll use it, otherwise, default to 8080.

const PORT = process.env.PORT || 8080

We have nothing in our dist folder, and the static middleware will be looking there. So let's fill that folder up:

npm run build

That should give you an index.html and a js and image file in dist. Now we can run locally to make sure all is working.

heroku local

In your browser go to http://localhost:5000. And it should be working. You can see the site is working.

But there's an error.

Production Error in HMR

Hot Module Reloading is still being added to the client main-bundle.js because it's still in the main.js

We can comment out in main.js for now.

// require("babel-runtime/regenerator")
// require("webpack-hot-middleware/client?reload=true")

In webpack.dev.js we can also comment out the HMR Plugin.

plugins: [
  // new webpack.HotModuleReplacementPlugin(),
  new webpack.NamedModulesPlugin(),
  ...
]

Okay, now we can rerun our build and restart heroku locally.

npm run build
heroku local

In Sum

git checkout heroku-final

And the error is gone.

Finally, let's push this up to heroku, by committing our changes and pushing them to heroku's git repo. We can see using heroku create added a git remote to our project in .git/config.

In terminal:

git commit -am "ready for production"
git push heroku heroku:master

Usually Heroku likes to use the master branch, but since we're on another branch, we can simply use this color syntax to specify which branch will be pushed to master in our remote. In this case the branch is heroku, but it could be any name.