Blogging with Middleman, Pt. 1

Side projects are a chance for me to experiment with tools that fall out of the scope of my (amazing) day job. This blog represents my first foray into using Middleman for blogging. Here are the first steps you should take when setting up a Middleman blog of your own.

To begin with, why am I using Middleman? I knew I wanted a static site. I started off with no clear deploy strategy in mind, and I wanted something so simple that I could just SFTP it to my Linode server and forget about it. Static React was out; as much as I like React and as cool as this setup sounds, I missed writing publication-style, semantic markup. Once I'd figured out that was what I wanted, it was a choice between Middleman and Jekyll. I've used both before and had good experiences with each. I went with Middleman because even though I'd used it before, I hadn't experimented with its blogging functionality.

As I dug deeper into Middleman, I discovered cool aspects of it that hadn't been immediately obvious. I'm having a lot of fun with it and completely recommend it to anyone else looking to start up a blog.

Setting the stage: rvm

Middleman is Ruby-based, so one of the first things I did was install Ruby Version Manager, or rvm, which lets you install and switch between multiple versions of Ruby. This means that a project doesn't necessarily depend on what you've got installed anywhere else — an upgrade to your system Ruby, or to Project A, won't affect Project B. Keeping dependencies local and specific has done wonders for my stress levels.

Once you've got rvm installed (I used the cURL command from the above link), you can install new versions with rvm install <versionNumber>. rvm list shows you what you've already got installed, and switching Ruby versions is rvm use <versionNumber>. As of writing, the minimum version of Ruby required for up-to-date Middleman is 2.2.2.

Creating a blog

To create a blog, follow the first instruction in the MM docs, and run gem install middleman. The next step — actually setting up the project — should be blog-specific. Instead of just middleman init, run middleman init —template=blog.

At this point, you have the framework of a basic Middleman blog in place. Run middleman server and then go to localhost:4567 to see what's been generated.

This stubbed-out blog is a great start, but you probably want to do some customization before you get publishing. Following are some of the first things I recommend doing, in the recommended order.

Setting your time zone

Before writing any articles, manually set your publishing time zone. middleman-blog ships with a nifty RSS feed generator, but publication times default to UTC, which probably isn't your local time. So let's take a sec right now and make sure your hordes of subscribers get accurate readings of when you publish.

(Also, if you hold off on setting your time zone and you only do it after you've written some articles, you will get cryptic errors about dates in frontmatter "not matching" and you will have to switch any articles with UTC timestamps in their frontmatter to bear your local timestamp. I will talk more about frontmatter later.)

You already have tzinfo-data installed (you can see it listed in your Gemfile), so go straight into your config.rb and add the lines:

require 'tzinfo'
Time.zone = 'US/Pacific'

And this time zone will now be used whenever you create a new article. You can find your time zone on this list.

Customizing YAML frontmatter

Now you can safely create your first article (!!) from the command line (!!) with middleman article <articleName>. A file called articleName.html.md will be created in your source dir, looking something like

---
title: foo
date: 2017-02-20 10:42 PST
tags:
---

This is YAML frontmatter, which provides per-article metadata.

You may not want this exact frontmatter. For example, I wasn't interested in tags, but I did want my articles to have subtitles. In this case, you can write your own article template.

Find the place in your config.rb that looks like this (I will be calling it the "blog block"):

activate :blog do |blog|
  # This will add a prefix to all links, template references and source paths
  # blog.prefix = "blog"

  # blog.permalink = "{year}/{month}/{day}/{title}.html"
  # Matcher for blog source files
  # blog.sources = "{year}-{month}-{day}-{title}.html"
  # blog.taglink = "tags/{tag}.html"
  # blog.layout = "layout"
  # blog.summary_separator = /()/
  # blog.summary_length = 250
  # blog.year_link = "{year}.html"
  # blog.month_link = "{year}/{month}.html"
  # blog.day_link = "{year}/{month}/{day}.html"
  # blog.default_extension = ".markdown"

  blog.tag_template = "tag.html"
  blog.calendar_template = "calendar.html"

  # Enable pagination
  # blog.paginate = true
  # blog.per_page = 10
  # blog.page_link = "page/{num}"
end

and somewhere in there, put the line

  blog.new_article_template = File.expand_path('../source/template.yml', __FILE__)

and create a file in /source called template.yml with the contents:

---
title: <%= @title %>
subtitle:
date: <%= @date.strftime('%F %R %Z') %>
---

Now if you run middleman article <articleName> again, your generated file will have contents like this:

---
title: foo
subtitle:
date: 2017-02-20 11:08 PST
---

title, subtitle, and date will be available as variables to use in blog structuring and templating.


The last thing I recommend in this step is editing (or at least being aware of) this line in the blog block of your config file:

# blog.default_extension = ".markdown"

Any files generated via middleman article will have this extension. You can change it to the equivalent but less verbose ".md", or to something else entirely (I'm using ".md.erb", for reasons I will cover later).

Remember to comment this line in to see changes ✌🏻

Pretty URLs, please!

Click into any of your articles and you will see that your URL ends in .html. Extensions in URLs is not best-practice web development, as it makes the URL harder to understand and means that changing frameworks (like, for whatever reason, switching from Middleman to .NET) could result in broken links. Pretty URLs give your users more stable, memorable addresses and help keep the inner workings of your site under the hood.

Middleman, like most devtools, ships with a way to implement pretty URLs. In the blog block, add the line:

  activate :directory_indexes

and you're set! From your index page, click through to an article, and you will see that the URL now ends in a / instead of .html.

If there are any pages that you don't want this done to, register that page in your config, in the "Per-page layout changes" section, like so:

page '/<page>.html', :directory_index => false

For example, I did this to my 404 page so that Github Pages would pick it up correctly (I will talk about GH Pages more in an upcoming post).

Writing and using SCSS

Luckily for me, Middleman comes equipped to transpile SCSS. By default, CSS-related files are looked for in the /stylesheets folder. If you want to customize this directory, you can do so by adding this line to your config.rb:

  config[:css_dir] = 'styles'

You can now refer to files in that dir from your templates (in my case, .erb files) using the stylesheet_link_tag variable.

Let's start off by creating /sources/styles/main.css.scss.

Multiple extensions may seem mysterious, but that's actually the crux of Middleman's power. Middleman lets you mix and match any parsers you want, and parses a file right-to-left according to its extensions. So file.css.scss means "this file will end up as CSS, but parse it as SCSS first". In the above section about generating articles, I mentioned that I changed the blog entry extension from the default .html.markdown to .html.md.erb. This tells Middleman to parse entries first as ERB (which lets me include fancy partials), then as Markdown, and that the end result is HTML.

Put some basic SCSS in your main.css.scss file:

body {
  font-family: sans-serif;
}

and add this line to inside the <head> tag of source/layout.erb:

    <%= stylesheet_link_tag :main, :media => "screen" %>

And now your site should look about 20 percent cooler.


I hope this gave you a good jumping-off point to blogging with Middleman! Stay tuned for a post about partials, syntax highlighting, and customizing your Markdown parser.

This is the second post in a series about creating this blog. Read the first post here.