Middleman

by Drew Barontini

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

Middleman is my preferred tool when it comes to building static sites. Not only do I use it on all my deployed sites, but I use it even when I’m prototyping an application that will ultimately move into a different system. Let’s talk about static-site generators and, more specifically, Middleman.

Static-site Generators

You may have heard of static-site generators before. A static-site generator simply takes your pre-compiled (and pre-processed) languages like Haml, Jade, Sass, LESS, Stylus, CoffeeScript, and others, and compiles them into the equivalent language that is understood by the browser; HTML, CSS, and JavaScript, respectively.

As far as static-site generators are concerned, Middleman isn’t the only kid on the block. Similar tools, like Jekyll, and GUI-style applications like CodeKit, Hammer, and Mixture, provide a similar feature-set for compiling pre-compiled languages into static HTML, CSS, and JavaScript files.

Beyond compilation of those aforementioned languages, Middleman provides several features for rapidly building websites, such as:

  • Creating master templates
  • Creating partial files
  • Template helpers (e.g. link_to, image_tag, etc.)
  • Frontmatter (page-specific variables)
  • Pretty URLs
  • LiveReload (for rapid local development)
  • Blog engine
  • Creating/reading local data files (.yml, .json)
  • Performance optimization (minifying, compressing)
  • Custom, community-built extensions (deployment, s3, etc.)

Middleman > GUI Apps

Why do I think Middleman is a better tool than equivalent GUI applications? Wait, didn’t you just read my list above? Kidding; let’s dig into some more in-depth reasoning.

Rails - Models & Controllers

Middleman is written in Ruby, and it follows similar conventions to the Ruby on Rails framework. If you work in that environment, it will feel very familiar, minus the Models and Controllers. Being written in Ruby, Middleman provides more power than any of the GUI-style applications.

Gemfile

If you’ve ever worked on a Rails project, the Gemfile will be familiar to you. It holds all of the Ruby gems used on that particular project. Middleman uses the same Gemfile, so setting up a Middleman project is as simple as running the following in the Terminal after downloading the project:

gem install bundler # If not installed
bundle install

That’s it. Middleman will go through and set up all the gems and get the project ready. Start the server with middleman server and you’re up and running.

This only applies to existing Middleman applications. You’ll need to initialize and set up Middleman on new projects.

Layout

Middleman contains a layout file (inside the source directory), layouts/layout.haml, that is your master layout for all of your pages. The = yield block in the file is where the individual page content from each of your view files will go. This is the same way that Rails layout files work.

You can create alternate layouts, or even nested layouts in Middleman.

Partials

In addition to the layout file, you can create as many “partial” files as you need. Let’s say that you have a header portion of your site that you reuse on several pages. You can create a partial file, and include that partial anywhere you need it.

%header.header
  %h1 The Title
  %p The subtitle for some secondary content.

I’ll be writing my HTML in Haml. If you don’t know Haml, I encourage you to take a look at the Haml site for more information.

In order to create a partial file out of our header markup, we simply create a new file, _header.haml, inside our source directory. Now, let’s include this partial file in a view file:

= partial 'header'

%p Here is some additional content on this page.

Notice the underscore (_) in the filename. All partial files start with an underscore. However, when we call the file, we don’t include the underscore.

Template Helpers

Middleman comes with built-in helpers that you can use in your view files. Let’s take a look at a few of them.

Link Helper

= link_to 'Link Title', 'http://www.example.com'

Outputs:

<a href="http://www.example.com">Link Title</a>

Asset Helpers

= stylesheet_link_tag 'application'
= javascript_include_tag 'application'

Outputs:

<link href="application.css" media="screen" rel="stylesheet" />
<script src="application.js"></script>

Lorem Ipsum & Placehold.it Helpers

= lorem.sentence      # returns a single sentence
= lorem.words 5       # returns 5 individual words
= lorem.paragraphs 10 # returns 10 paragraphs

Lorem ipsum text helpers

= lorem.image('300x400')
-# -> http://placehold.it/300x400

Placeholder image helper

Those are just a few of the many template helpers that Middleman provides. Be sure to read the documentation to learn about all of them.

Custom Helpers

In addition to the built-in helpers in Middleman, you have a file, config.rb, that allows you to write custom helpers that you can use in your view files. Let’s look at a couple simple examples:

helpers do
  def pretty_date(date)
    date.strftime('%B %d, %Y')
  end
end

config.rb

Here we have a pretty_date() helper that we can then use in our view files to format our dates:

%time= pretty_date('2013-12-03')

Haml <time> tag

Which will compile to:

<time>December 03, 2013</time>

What if we wanted to add an active class to our navigation items, when on the associated page, to give a specific styling to that navigation element? Well, let’s create another helper:

helpers do
  def is_page_active(page)
    current_page.url == page ? {:class => 'is-active'} : {}
  end
end

config.rb

And in our view file:

%nav.nav
  %ul
    %li{ is_page_active('/') }
      = link_to 'Home', '/'
    %li{ is_page_active('/articles/') }
      = link_to 'Articles', '/articles/'

_nav.haml partial file

And this compiled will look like as follows when on the Home page:

<nav class="nav">
  <ul>
    <li class="is-active"><a href="/">Home</a></li>
    <li><a href="/articles/">Articles</a></li>
  </ul>
</nav>

Compiled _nav.haml file

Frontmatter

What in the world is “Frontmatter?” Is this a Star Trek thing? No, Frontmatter simply lets you write a block of YAML or JSON data at the top of a view file that you can then, in turn, use in that file. Let’s look at an example:

---
title: My Page Title
---

%h1= current_page.data.title

This outputs:

<h1>My Page Title</h1>

Now, this isn’t a very practical example, but you get the idea. We just add the Frontmatter declaration to the top of the file, and then we have the ability to use those variables within the page. Pretty cool, huh?

Frontmatter & Partials

Let’s look at a more advanced, practical usage of Frontmatter, but this time we’ll use it in conjunction with a partial file to show some of the power in Middleman.

First, we’ll create some Frontmatter. We want to add some variables about each of our blog posts that can be used in a post header partial.

---
title: Middleman
date: 2014-01-07
---

Alright. Now that we’ve defined a title and a date for this particular blog post, we want to use that local data in a partial. How do we do this?

---
title: Middleman
date: 2014-01-07
---

= partial 'post_header', :locals => { :data => current_page.data }

Whoa! What’s going on here? Well, we’re including the partial just like we did before, but we’re passing a second argument (:locals), and passing the current_page.data, which is the Frontmatter for this particular page.

Now, in our post_header view file, we have access to each page’s Frontmatter through data, and we can just output the correct markup.

%header.post-header
  %h1= data.title
  %time{ datetime: data.date }= pretty_date(data.date)

_post_header.haml

Notice how we’re using that same pretty_data() helper that we defined earlier to properly format our date.

And this compiles to:

<header class='post-header'>
  <h1>Middleman</h1>
  <time datetime="2014-01-01">January 7, 2014</time>
</header>

_post_header.haml

Local Data

In addition to using Frontmatter in individual files, you can also create a YAML or JSON file at the root of your project, inside a data directory, that you can then use within your view files. Let’s look at an example.

We create a data/list.yml directory/file to store a list of links that we want to add to a page of our site. Instead of having to manually create new markup, we can just write some simple YAML, and then loop through and output the data in the file.

links:
  - http://drewbarontini.com
  - http://envylabs.com
  - http://www.codeschool.com

Now, in our view file:

%ul
  - data.list.links.each do |link|
    %li= link_to link, link

Which now outputs each of our links.

<ul>
  <li><a href="http://drewbarontini.com">http://drewbarontini.com</a></li>
  <li><a href="http://envylabs">http://envylabs.com</a></li>
  <li><a href="http://www.codeschool.com">http://www.codeschool.com</a></li>
</ul>

Super simple and really useful.

Production-ready Configuration

In addition to just compiling assets and providing several helpers, Middleman allows you to specify a “build' configuration for minifying your HTML/CSS/JavaScript, gzip-ing files alongside your regular files for your web server to serve up, and compressing images (via an extension). How do we do this?

In your config.rb add the following:

activate :minify_html

configure :build do
  activate :minify_css
  activate :minify_javascript
end

In order to get the HTML minification to work, add this to your Gemfile:

gem 'middleman-minify-html'

And then run bundle to install that gem.

Now, when you run the middleman build command, it will minify your HTML, CSS, and JavaScript when building the static files.

Extensible

There is a fantastic community behind Middleman, and there are some great extensions that you can use in your projects. Take a look at the Middleman extensions directory to see what’s available.

Building the Static Files

Once you’ve written all your Ruby, Haml, Sass, and CoffeeScript using all these cool features in Middleman, you’ll need to build the static files. In order to do this, you just need to run the following command in the Terminal:

middleman build

Middleman will create a build directory that contains the static files your server will read. You can just upload these files to your web server via FTP, and you’re good to go. Or, you can do some more fancy things with the deployment. Let’s look at that next.

Deployment

Instead of manually uploading the build files to your server via FTP, we can create a deployment script using something called a Rakefile, which is just a file that contains executable Ruby code. You have a few different options for deploying your site.

GitHub Pages

A popular solution these days is to serve your site on GitHub Pages. When you run the rake task in the Terminal, which is what is created in the Rakefile, it will:

  1. Run the middleman build command
  2. Go into the build directory
  3. Initialize an empty Git repository
  4. Add the repository URL specified as the remote
  5. Add all of the build files
  6. Force push the files to the gh-pages branch

When set up correctly, you just run rake deploy in the Terminal, and your site’s static files will be automatically pushed up to your GitHub Pages site. Awesome, right?

Be sure to follow GitHub’s documentation to familiarize yourself with the process for GitHub Pages.

FTP Server via rsync

If you have your own site with FTP, you can use something called rsync.

rsync is an open source utility that provides fast incremental file transfer.

The process is similar, but the files are transferred using rsync rather than Git.

You’ll need to be able to SSH into your server in order to use this method.

Getting Started

If you want to get started with Middleman, I’ve created a repository, ”Baseman,“ which is a base Middleman application setup that I like. It uses Haml, Sass, and CoffeeScript, sets up the config.rb the way I like and, in the README, there is instructions on creating those deploy scripts.

That’s All, Folks

That’s it. I hope you enjoyed this look at Middleman. There is a lot more to Middleman than what I talked about so, if you’re interested in learning more, I encourage you to take a look at the Middleman site.

Credit: I also want to give a shout-out to my friend, Arron Mabrey, who is the sole reason I got hooked on Middleman. I can’t thank him enough :)