Deploying a Yeoman Web App with SASS, Grunt, and Bower support to Heroku

Note: This assumes that you know how to use the listed dependencies above and that your application is in a state of completion that is ready to be deployed. If not, please refer to this documentation.

Steps to deployment

1. Setup Heroku

NOTE: If you have used Heroku before, skip this step.

Assuming that you have never worked with Heroku before, you will need to download the Heroku Toolbelt for your respective operating system. Once installed, go to heroku.com and create an account and verify your email address if necessary. Next open up your terminal/CLI and type the following command:

heroku login  

This will ask you for the username and password for the account that you just created. Assuming that your credentials are correct, you should receive a success message. Now you are logged in.

2. Create a Project

After authenticating our user, we now need to create an application. To do so, use the following command:

heroku create [app-name]  

Replace [app-name] with your application name. Be sure to NOT use spaces or special characters. It should be like a URI slug in nature. Also the name that you give your application has to be unique to Heroku. If it fails, try try try again. After a successful name has been selected, Heroku will add an addition remote branch to your repository.

3. The Procfile

The Procfile is a special type of configuration file that is unique to Heroku. It allows you to customize your server settings like you would for Apache or NGINX. By default, when you compile a project, Grunt throws all of the dependencies in a dist/ folder. Therefore we need to tell Heroku where the index of the application will reside. That is where the Procfile comes in.

To get started, create a new file titled Procfile in the root of your project. NOTE, do not add any preceeding or trailing prefixes or punctuation. This will prevent it from working. Next add the following line to your newly created Procfile:

web: node web.js  

Once finished, save the file and close it. We won't need to do anything else.

4. The web.js file

If you remember from the step above, we created a new file that essentially tells Heroku to run web.js using Node. However currently at this point in time we do not have a file anywhere in our project by this name. Just like the Procfile, create a new file titled web.js in the root of the project.

Within this file paste the following code and save it:

var gzippo = require('gzippo');  
var express = require("express");  
var logfmt = require("logfmt");  
var app = express();

app.use(logfmt.requestLogger());

app.use(gzippo.staticGzip("" + __dirname + "/dist"));  
    var port = Number(process.env.PORT || 5000);
    app.listen(port, function() {
    console.log("Listening on " + port);
});

At it's core, this snippet of code is very simple. Basically what we are doing is we are starting a basic Express (Node) server in the /dist directory, displaying the content with a GZIP compression, and using an Express logging package to display any and all errors/system messages. If you notice the variable process.env.PORT, this is a global environment variable that Heroku uses for its Node projects.

5. Modifying your package.json

Assuming you are already familiar with Node and how it operates, that majority of the information associated with your application is listed out in this file. Heroku heavily relies on this file (as you would expect) for fine-tuning your setup. With that said, there are a few things that we need to do.

Production dependencies

When you deploy a Node-based project to Heroku, Heroku automatically sets the Node environment variable to production; meaning that Node Package Manager will only install the packages listed within the "dependencies" object in you package.json file. If we were to leave this untouched, Grunt would not be able to comiple your project because none of the required packages are available.

So what we need to do is pretty simple. Simply copy the entire "devDependencies" object and paste/replace over the "dependencies" object. Be careful to leave the object keys untouched.

Server and installation dependencies

Now that we have essentially replicated our development environment on top of our production environment, there are still a few things that we need to add.

We need to assume that Heroku has no idea what we have installed globally on our own machines. Therefore meaning that Heroku won't be able to use Bower or the Grunt CLI unless we tell it to install it. To do so, simply enter the following command:

npm install bower grunt-cli --save  

Make sure that the --save option is used otherwise your package.json will remain unmodified.

Next we need to install all of the Node packages that we referenced in the web.js that we created a couple steps prior. To install these, enter the following:

npm install express gzippo logfmt --save  

The "postinstall" command

Your package.json file in addition to store dev or production dependencies can issue commands that will happen pre or post install. In this instance, we want to tell Heroku that upon the successful completion of the installation step of all of our Node packages, we want to install all of our Bower dependencies and then finally build the application using a grunt task. So to do this, within the "scripts" object, we need to add a new line with the following key value pair:

"postinstall": "./node_modules/bower/bin/bower install && grunt build"

NOTE: If you have created a custom Grunt task for your production deployments, feel free to replace "build" with the name of that task.

We are now finished with our package.json file, save and close it.

5. Adding Ruby and SASS

If you have elected to not use SASS or you are using the LESS preprocessor, skip this section.

If we were to deploy our application to Heroku in it's current form, Heroku would automatically detect that our application uses Node; thus installing Node within the app's container. This is great except for one problem: during the building process, Grunt will need to use Sass, which requires Ruby, to build the app's CSS. Currently the Heroku container does not have either of these installed and will fail. Every time.

To fix this error, we will need to require the SASS gem (Ruby calls its packages/dependencies gems). First create a new file titled Gemfile with the following lines of code included:

source "http://rubygems.org"  
gem "sass"  

Finally we need to include a file titled Gemfile.lock. Essentially this is a file that would have been automatically created had we run the gem install command. If you want more information on this file type, you can find it here.

Once you have created the file, paste the following code:

GEM  
  remote: http://rubygems.org/
  specs:
    sass (3.4.5)

PLATFORMS  
  ruby

DEPENDENCIES  
  sass

Once finished, save the file and then close it.

NOTE: Depending on the version of grunt-sass your application uses, you may need to adjust the version of sass within this file.

6. Buildpacks

Buildpacks within Heroku tell the system what type of code-sets your application uses to serve its content/functions. Heroku will then in turn look for your dependency listings to install the necessary dependencies. More often than not, you will only need one buildpack. However in this instance we will need two buildpacks: one to install Node and our Node packages, and a second to install Ruby and our SASS gem.

First lets add Node buildpack. To do so enter the following command into your CLI:

heroku buildpacks:add https://github.com/heroku/heroku-buildpack-nodejs.git  

Next lets add the Ruby buildpack. Enter the following:

heroku buildpacks:add https://github.com/heroku/heroku-buildpack-ruby.git  

Assuming that everything was entered correctly, if you use the heroku buildpacks command, your command line should return something like this:

=== [app-name] Buildpack URL
1. https://github.com/heroku/heroku-buildpack-nodejs.git  
2. https://github.com/heroku/heroku-buildpack-ruby.git  

This means that Heroku will install both the Node and Ruby buildpacks followed by the dependencies that we have referenced in our project.

7. Deploy your application

Now that we have finally finished the configuration of our application, we now need to add ALL of the new files that we have created to the repository that is associated with this project. If any of the files that were created in this tutorial are not added, Heroku will ignore them. Commit the changes, push the changes to your standard remote repository and then finally enter the following command to deploy the app to Heroku, and then initiate the compilation process:

git push heroku master  

Depending on the size of your application as well as your internet connect, this could take a little while; especially if this is your first deployment. In subsequent deployments, Heroku will begin caching packages and tasks to help speed up the deployment process. Assuming there are no errors, Heroku will reward you with a success message within your CLI notifying you that the deployment has completed.

8. Finishing and scaling

While this topic extends way beyond the scope of this step-by-step explanation, lets assuming for a second that we just want to get this application up for client review; and this is not a production environment. In this case lets just use Heroku's free dyno. It is worth noting that this tier does have some speed issues, and if the server is "sleeping" could require a little bit of time to spin up; but its free. To scale our app to use a single dyno, enter the following command:

heroku ps:scale web=1  

Assuming everything went through successfully, you should see this message telling you that you are up and running:

Scaling dynos... done, now running web at 1:Free.  

If you see that, your application is up and is now ready for your viewing pleasure.