Building Sites with Middleman

lean publishing

This article was published a while ago and may contain obsolete information!

I make a lot of websites, and I have a certain toolkit that I use to build them. The most useful things I use are:

layouts and partials so I only need to set things up once

haml for writing html, since I don’t like closing tags

Bootstrap and sass for writing css

Markdown for formatting large blogs of content

coffeescript for JavaScript

Middleman is a static site generator, which means that it takes a bunch of source files, does some stuff with it, and produces static HTML, CSS, Images, and Javascript that can be hosted on a basic server somewhere, including hosting on S3 or Github Pages so you don’t need to consider a server.

Middleman is written in Ruby, so it’s our familiar toolset, and unlike Jekyll it uses Sprockets, which is the same asset pipelining system that Rails uses. So you get all the benefits of using a robust system that works for Rails apps without having to learn a bunch more things.

In the node world Yeoman does something similar, but I personally have had poor luck getting Grunt to work reliably in practice.

Setting up a simple static site with Middleman

One of the problems with starting with Middleman is that there are so many places to start. Lets look at how to setup a basic middleman site with bootstrap-sass, haml, and bower. First thing is to install middleman:

This creates 4 files in the main directory, Gemfile and Gemfile.lock, which we know and love, config.rb which configures how middleman generates the site, and source which are the sourcefiles of the site.

Gemfile

By default, middleman installs the middleman-livereload plugin, so in development mode any browers that have a page open with refresh when you save a file. This makes testing a lot easier. We can install other gems here to add different functionality. Let’s add a few of these now:

The first two gems expand the functionality of middleman, one to add tasks to push the final site build to s3, gh-pages and a whole bunch more, and the second to make it easier to build bootstrap navbars.

The file two are including bootstrap-sass – the same that we use for rails sites – and jquery. These get included into the sprockets asset path, so you don’t need to maintain them in your project. (We’ll also see below how to integrate bower components into your project.)

Tweaking Middleman

config.rb is where we configure how middleman itself works.

# For custom domains on github pagespage"CNAME",layout:falseset:css_dir,'stylesheets'set:js_dir,'javascripts'set:images_dir,'images'# Better markdown support# set :markdown, :tables => true, :autolink => true, :gh_blockcode => true, :fenced_code_blocks => true# set :markdown_engine, :redcarpet# Turn this on if you want to make your url's prettier, without the .htmlactivate:directory_indexes# Automatic image dimensions on image_tag helper# activate :automatic_image_sizes# Easier bootstrap navbarsactivate:bootstrap_navbarconfigure:developmentdoactivate:livereloadend# Build-specific configurationconfigure:builddo# Any files you want to ignore:ignore'/admin/*'# For example, change the Compass output style for deploymentactivate:minify_css# Minify Javascript on buildactivate:minify_javascript# Enable cache busteractivate:asset_hash# Use relative URLsactivate:relative_assetsend# This will push to the gh-pages branch of the repo, which will# host it on github pages (If this is a github repository)activate:deploydo|deploy|deploy.method=:gitdeploy.build_before=trueend

Lets go through this in detail.

page "CNAME", layout: false says to move the file called CNAME over without wrapping in the main layout. Since this file doesn’t have .html in the name, it would otherwise get ignored. This file is for having a custom domain on Github Pages, if that’s the sort of thing you are in to.

The set commands are there to configure different middleman settings, here to show where the various stylesheet, image, and css directories are.

activate :directory_indexes with enable pretty urls. Directory indexes means that files named about.html will actually get generated into a file called /about/index.html, and will rely on the underlying server to have /about actually show the directory “index” page, making the urls prettier. This doesn’t work on all servers but works on most of them. This plugin will actually rewrite the output of the link_to tags, so you don’t need to adjust your templates to work.

activate :bootstrap_navbar is an extension that we added in the Gemfile, which makes it easier to generate bootstrap navbars. Extensions generally work in three ways: they add helper methods, they change the way that the sitemap is processed, or they add different commands to the “middleman” command.

We see an example of that at the bottom of the config.rb file, where we configure the deploy extension:

This also takes some configuration, and in this case it set to deploy to github pages, and to make sure that it generates the site before doing so. Here is the middleman-deploy github page with documentation.

There are two sections that each configure a different middleman environment. The first is used when you run middleman server to look at the site locally:

configure:developmentdoactivate:livereloadend

The final section is configuring the build process, when you run middleman build and it creates the generated files in the build directory. The entry below ignores certain files for the build, and runs minifiers over the css and javascript, and turns on cache busting.

In this usage, this is similar to the way that rails layouts work. I’m using the ~ HAML operator inside of = here because I want to make sure that it doesn’t do anything wonky with the indention on <pre> blocks, btw.

Middleman has a concept of nested layouts, which lets you have wrap an a layout around another one. I think that this is confusing in practice, but as an example you could have a layouts/sidebar_layout.erb that looked like:

The YAML preable the preyaml

Metadata about the template is included in a block of text at the top of the file, which gets pulled off to set things that the templating system can use later. On the top of this file that I am editing right now, it looks like this

---
title: 'Building Sites with Middleman'
subtitle: 'lean publishing'
tags: middleman, ruby, howto
header_image: books.jpg
---
I make a lot of websites, and I have a certain toolkit that I use to build...

The title, subtitle, tags and header_image attributues are available in the templates as page data, so you can access them like:

%h1= current_article.title
%h2= current_article.data['subtitle']

title is built into middleman, subtitle and header image are just some random things I made up. The tags attribute is part of the middleman-blog extension which we will cover below.

How the build works

When you run middleman server or middleman build, middleman loads up the configuration file in config.rb. It creates a sitemap based upon the files in the source directory as well as other directives inside of the config.rb file.

By default it only includes files like .html.erb and .js, but you can set it manually include a non-template file (like our page "CNAME" above or create other proxy files. Proxy files are a way of seperating out the templates from the source data.

Then each entry in the sitemap the file is processed (based upon the extension, so scss -> js, haml -> html, etc.) into the build directory. Helper methods are available inside of the templates for things like javascript_include_tag, stylesheet_link_tag, link_to and image_tag and all of the rest.

middleman server

Starting the server in preview mode will start a local server on port 4567 that generates the files on demand. If you have livereload enabled this will automatically trigger a page refresh for any open browsers, so you can tweak and look at things as you go.

Inside of your templates, config.environment == :development when you are in preview mode. So, if there are some things that you don’t want to push to the live site but are useful for development, you can switch them on and off using that mechanism.

middleman build

This does basically the same thing as the server, but the templates are generally further processed. Cachebusting can be enabled, and you can include tracking code if config.environment == :build is true. This goes through all of the files in source that look like webfiles and places them in the build directory.

And easy way to check out what you have there is by cding into the build/ directory and running a simple webserver to serve the pages. Relative links don’t work when you open the file directly in the browser, so you need to use an actual webserver.

$ cd build
$ python -m SimpleHTTPServer

And then open a new browser on port 8000.

middleman deploy

In the basic :git setting that we have above, middleman deploy will build the site into the build/ directory, switch that directory to the gh-pages branch, and push it to origin. Assuming that you are hosting your repo on github, this will publish the static content on github pages.

If you want to use a custom domain then you need to create a CNAME file in source/ with the domain name, and set up your DNS records to match.

One thing to note is that while changes to the pages seem to deploy quickly, it takes a long time for the first push to github pages to show up, on the order of 10-15 minutes.

Building a blog

There are two good extensions for building a blog with middleman. The default template for blog is sort of confusing in the way that it’s laid out, mainly because it gets rid of the layouts/ directory, but let’s go through it and see how it’s supposed to work:

This lets us keep drafts in git and doesn’t force us to commit to a date until we are ready to publish it. There are published and date attributes that the default blog extension knows about to turn it on and off, and is a good example of something that you can see in development but not production, but that still leaves to moving files around manually to adjust the date.

What does it add

In addition to the sitemap, we now have a blog, article, and tag concept inside of the middleman app. Articles are represented as pages (by default using markdown) but the tag and calendar templates are actually more like proxy templates than file templates, and when the site is generated middleman will iterate over then to produce many output files from one template.

This should be enough to get you started, and more documentation is here . At this point it really becomes a design and development challenge, not figuring out how to use the tool.

Go get started

Middleman gives you all of the front-end developer benefits of using a system like Rails, but outputs static content than can be served anywhere without any dependancies. Many sites don’t really require all that for them to run, and it’s crazy to me that something as read heavy as a blog often can’t perform well under load given that it’s just serving up the same old stuff over and over again. You want to have some tooling to make it easier, but it doesn’t need to be run time tooling.

See also

Lets build on our command line url exploring tool to look at how we can interact with Twitter. We are going to cover how to make a script that will pull information out of twitter, how to deal with its rate limiting, and how to interact with users on Twitter itself.
Twitter uses OAuth 1.0A as a way to authenticate requests. As a script writer, this is super annoying, because you can’t just stick a username and password in the environment and go from there.

Some scripts work well because they are self contained and don’t have a lot of dependancies, like the hosts on your network tracker.
Others scripts - have more code than fits into a single file - multiple options and switches - have an extensive set of dependancies
And on those cases, its better to make a gem and use thor
Hammer of the Gods Lets figure out how to make some command line tools and package them up so that they can be shared and used by other people.

How much information do you bleed?
Ever wonder who is else is using your network? Or,who has actually showed up at the office?
Networking primer The simplest thing we can do to make this work is to check to see which devices have registered themselves on the network. As devices come and go, they connect automatically, so we will have a pretty good idea if people are there or not.