How I deployed Middleman to Heroku

I've recently redesigned this website and it is now built using Middleman.

Middleman is a static site generator using all the shortcuts and tools in modern web development

This post is about how I deployed the site to Heroku.

Building the site

Middleman is a static site generator, as such, we need to figure out how to get the site built when we deploy. This saves having to build the site and commit the result before deploying.

Heroku will automatically attempt to execute a rake task called assets:precompile.

This was originally for the benefit of Rails, but we can take advantage of this now for our own needs.

I created a new Rakefile and added the following.

1
2
3
4
5
namespace :assets do
  task :precompile do
    sh 'middleman build'
  end
end

The task simply shells out to call middleman build which builds the site automatically when the site is pushed to Heroku. Middleman will output all files to ./build.

Serving the site

The process of serving a static Middleman site on Heroku is quite straight forward once you understand the basics. The site will be running as a Rack app, so we'll need a config.ru file. Here is what mine looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
require 'rack'
require 'rack/contrib/try_static'

# Serve files from the build directory
use Rack::TryStatic,
  root: 'build',
  urls: %w[/],
  try: ['.html', 'index.html', '/index.html']

run lambda{ |env|
  four_oh_four_page = File.expand_path("../build/404/index.html", __FILE__)
  [ 404, { 'Content-Type'  => 'text/html'}, [ File.read(four_oh_four_page) ]]
}

The Rack::TryStatic section is how we serve up the static files that Middleman builds when the site is pushed to Heroku. Middleman outputs all files into ./build.

If no page is served from the Rack::Trystatic app, the 404 page is served using the next run section.

UPDATE: Make sure to add rack-contrib to your Gemfile as pointed out by @fulljames.

I decided to use the Puma web server to do the actual web serving of the files as I had never used it before and wanted to try it out. I added Puma to my Gemfile and created this Procfile.

1
web: bundle exec puma -p $PORT

Puma is working great.

It's as simple as that. Once pushed to Heroku, everything just works.

Keeping the site alive

I'm using a single free Dyno to serve the site and it's seriously fast. Granted, this site is not receiving lots of traffic, but it's still very quick.

The only downside of a single Heroku Dyno is that it will idle after a period of inactivity, which can happen often unless you get lots of regular traffic.

I order to keep the site alive, the sites needs to be requested periodically.

I'm using Pingdom for this.

Conclusion

Middleman is really easy to work with, especially for a Rails developer, and Heroku serves the site very well. I would definitely recommend the combination of Middleman and Heroku.