Category Archives: Uncategorized

How to Deploy an AngularJS/Rails Single-Page Application to Heroku

Note: this post is somewhat aged. You may be interested to check out the Rails 5/Angular 2 version, which still applies somewhat to Rails 4/Angular 1.x.

Why deploying a single-page application is different

Before I explain how to deploy an Angular/Rails application to Heroku, it might make sense to explain why deploying a single-page application (SPA) is different from deploying a “traditional” web application.

The way I chose to structure the SPA in this example is to have all the client-side code a) outside Rails’ the asset pipeline and b) inside the same Git repo as Rails. I have a directory called client that sits at the top level of my project directory.

Gemfile
Gemfile.lock
README.rdoc
Rakefile
app
bin
client <-- This is where all the client-side code lives.
config
config.ru
db
lib
log
node_modules
spec
test
tmp
vendor

When I’m in development mode, I use Grunt to spin up a) a Rails server, which simply powers an API, and b) a client-side server.

In production the arrangement is a little different. In preparation for deployment, the grunt build command poops out a version of my client-side app into public. Rails will of course check for a file at public/index.html and, if one exists, serve that as the default page. In fact, if you run grunt build locally, spin up a development server and navigate to http://localhost:3000, you’ll see your SPA served there.

But it would be pretty tedious to have to manually run grunt build before each deployment. And even if you somehow automated that process so grunt build was run before each git push heroku master, it wouldn’t be ideal to check all the code generated by grunt build into version control.

Heroku’s deployments are Git-based. The version of my client-side app that gets served will never be checked into Git. This is the challenge.

Automatically building the client-side app on deployment

Fortunately, there is a way to tell Heroku to run grunt build after each deployment.

First let’s get grunt build functioning locally so you can see how it works.

Change the line dist: 'dist' to dist: '../public' under the var appConfig section of client/Gruntfile.js. For me this is found on line 19.

Now remove the public directory from the filesystem and from version control. (Add public to .gitignore is not necessary.)

$ rm -rf public

If you now run grunt build, you’ll see the public directory populated with files. This is what we want to have happen in production each time we deploy our app.

Configuring the buildpacks

Next you’ll want to add a file at the root level of your project called .buildpacks that uses both Ruby and Node buildpacks:

https://github.com/jasonswett/heroku-buildpack-nodejs-grunt-compass
https://github.com/heroku/heroku-buildpack-ruby.git

You can see that I have my own fork of the Node buildpack.

In order to deploy this you might need to adjust your client/package.json and move all your devDependencies to just regular dependencies. I had to do this. Here’s my client/package.json:

// client/package.json

{
  "name": "lunchhub",
  "version": "0.0.0",
  "description": "The website you can literally eat.",
  "dependencies": {
    "source-map": "^0.1.37",
    "load-grunt-tasks": "^0.6.0",
    "time-grunt": "^0.3.1",
    "grunt": "^0.4.1",
    "grunt-autoprefixer": "^0.7.3",
    "grunt-concurrent": "^0.5.0",
    "grunt-connect-proxy": "^0.1.10",
    "grunt-contrib-clean": "^0.5.0",
    "grunt-contrib-compass": "^0.7.2",
    "grunt-contrib-concat": "^0.4.0",
    "grunt-contrib-connect": "^0.7.1",
    "grunt-contrib-copy": "^0.5.0",
    "grunt-contrib-cssmin": "^0.9.0",
    "grunt-contrib-htmlmin": "^0.3.0",
    "grunt-contrib-imagemin": "^0.7.0",
    "grunt-contrib-jshint": "^0.10.0",
    "grunt-contrib-uglify": "^0.4.0",
    "grunt-contrib-watch": "^0.6.1",
    "grunt-filerev": "^0.2.1",
    "grunt-google-cdn": "^0.4.0",
    "grunt-newer": "^0.7.0",
    "grunt-ngmin": "^0.0.3",
    "grunt-protractor-runner": "^1.1.0",
    "grunt-rails-server": "^0.1.0",
    "grunt-shell-spawn": "^0.3.0",
    "grunt-svgmin": "^0.4.0",
    "grunt-usemin": "^2.1.1",
    "grunt-wiredep": "^1.7.0",
    "jshint-stylish": "^0.2.0"
  },
  "engines": {
    "node": ">=0.10.0"
  },
  "scripts": {
    "test": "grunt test"
  }
}

I also registered a new task in my Gruntfile:

// client/Gruntfile.js

grunt.registerTask('heroku:production', 'build');

You can just put this near the bottom of the file next to all your other task registrations.

And since the Node buildpack will be using $NODE_ENV when it runs its commands, you need to specify the value of $NODE_ENV:

$ heroku config:set NODE_ENV=production

Lastly, tell Heroku about your custom buildpack (thanks to Sarah Vessels for catching this):

$ heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git

After you have all that stuff in place, you should be able to do a regular git push to Heroku and have your SPA totally work.

Don’t Use an Amateur Email Address

Have you ever gotten a business card from, e.g., a hair stylist and the email address on the card was something like kaylas_hairdesigns@gmail.com? An email address like that just screams “I’m an amateur. I don’t take myself seriously enough to invest the 10 minutes and 14 dollars that it would take to register my own domain.”

At the time of this writing, the email subscriber list for CodeWithJason.com has a little over 100 people on it. I would estimate that over 90% of the subscribers have an @gmail.com, @yahoo.com or @hotmail.com email address. These are people who supposedly care enough about their job search to sign up to get regular emails from me about it. Yet they apparently haven’t bothered to get themselves a non-Gmail email address. If that’s the state of affairs with this sample, what’s it like in the general population? Probably pretty fucking bad.

The reason I bring this up is to illustrate that if you get yourself a custom email address, you’re probably already ahead of 90% or more of your job-seeking competitors. The bar is low out there.

Some people have asked me what a good domain to register might be. For me personally, I have my own S Corp through which I do most of my freelance programming work. The name of my one-man business is Ben Franklin Labs. The domain I’ve registered is benfranklinlabs.com and my email address is jason@benfranklinlabs.com. That’s a good example for somebody like me who has his or her own business entity. I realize that it’s likely that you do not.

It’s probably more likely that you normally work as a full-time employee as opposed to a contractor like me. In that case, I would just recommend using .com. One of my personal domains is jasonswett.net (jasonswett.net instead of jasonswett.com because I wanted it to rhyme) and the email address I use under that domain is jason@jasonswett.net. It doesn’t matter a whole bunch what you choose. Just about anything is better than a Gmail address.

Hello world!

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!