Today we are going to look at Middleman, a ruby based static site generator. Middleman will allow us to leverage modern development tools such as HAML and SASS to build static sites. Today we will setup a basic middleman project, explore its folder structure, then look at the build and publishing tools.
I've got a basic Ruby repository setup for our project, and it is open sourced as Rudiment. I'll be using it to cover some modern elements of front end web dev. Let's get started!
First off I'll install bundler and initialize middleman in my current folder with:
$ gem install bundler
$ gem install middleman
$ middleman init .
We can now start up middleman and confirm it's all working by running
middleman. Note that this is shorthand for middleman server.
$ middleman
Now we can visit http://localhost:4567 to see that our server is running.
Middleman provides a handy link to its documentation, which is wonderful. There
are a lot of static site builders out there, and the reason I often come back to
Middleman is both the quality of its documentation and third party plugin
support -- but we'll get to those later.
Middleman also provides a configuration screen via localhost:
http://localhost:4567/__middleman this allows you easy access to a browsable
sitemap. This sitemap is really
helpful because it allows you to see every file that Middleman is parsing, and
what its output is.
For instance, if we open up the index.html tab we can see its source file is
source/index.html.erb, its compiled path is index.html, and even that file
specific data that is being sent up to the layout for use in the title. This
level of verbosity is really useful when tracking down little bugs in your
sites!
The configuration screen also allows us to browse the internal configuration of Middleman itself. We won't need this today, but will use it a lot more in the future.
Let's take a look at the files and folders that Middleman generated for us. In
our top level we have a config.rb, that's the top level configuration for our
project, and is where the internal configuration screen gets its properties
from.
Next we have a Gemfile and corresponding Gemfile.lock. The lock file is
automatically generated from the Gemfile when you run bundler. Our Gemfile
lists Middleman and some platform specific dependencies. Together these files
make our project easily portable, as we can just gem install bundler and
bundle to have our project running on most any system with Ruby.
We have a handful of hidden files that have little impact on our html/css, but just make the project more portable and add to developer quality of life. These include ruby environment settings, a localized gemset, specified Ruby version, and git ignore rules.
Now on to the important stuff: the source folder. Inside of it we have
places to keep images, javascript files, layouts and stylesheets. Any top level
html file like the index.html.erb will be compiled into a page.
They aren't generated by default, but Middleman supports a few other directories
here. You can make a lib directory to hold ruby files, and these function like
helpers in Rails. You can also have a data folder with YAML or JSON files.
These data files are parsed and made available as objects to your pages, so you
independently change your data and how it is rendered. This is a big time saver.
Finally, when you build your site, you'll get a cleverly named build folder
with the output.
Just by running middleman build we get a fully built and ready to publish
version of our site. Let's try that now:
$ middleman build
Now our build folder exists and is populated with the initial site that
Middleman ships with. We can see that the index content has been applied to
the template and the title has been filled in properly from the data settings
inside of the index page. We could easily drop the contents of our build
folder onto S3, github, or any other static host to have our site live. There
are a lot of Middleman packages to automate this for us, too!
Let's take a look at our layout.erb and index.html.erb page. Both of these
are written in ERB, or Embedded Ruby templating syntax. It's just basic html
with some Ruby hooks in it. The layout file is pretty simple.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Use the title from a page's frontmatter if it has one -->
<title><%= current_page.data.title || "Middleman" %></title>
<%= stylesheet_link_tag "site" %>
<%= javascript_include_tag "site" %>
</head>
<body>
<%= yield %>
</body>
</html>
In the title, we populate it with page data, or the string Middleman
if that
doesn't exist. There are a couple link tags to bring in the site stylesheet and
javascript file. These call out to the configuration settings and lookup the
default location for those file types and create a proper link or script tag as
appropriate.
The line that tends to confuse people is the <%= yield %> call. Ruby
encourages most functions to take a block. Calling yield just has the
interpreter parse the contents of that passed block at that location. This means
that our pages, like index.html.erb, are passed to the layout and placed
inside of said layout when that yield is called. There isn't any magic here, we
just dump the parsed contents of that file where yield goes.
The index.html.erb is even simpler.
---
title: Welcome to Middleman
---
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 340" class="middleman-logo" aria-labelledby="middleman-logo__title" role="img">
<title id="middleman-logo__title">Middleman</title>
<path class="middleman-logo__top-left-bar" fill-opacity=".45" d="M0 40L200 0v30L0 60z"/>
<path class="middleman-logo__top-right-bar" fill="#fff" d="M200 0l200 40v20L200 30z"/>
<path class="middleman-logo__left-m" fill-opacity=".45" d="M0 78v184l45 5V152l45 83 47-83v129l53 7V52l-57 8-43 83-43-70z"/>
<path class="middleman-logo__right-m" fill="#fff" d="M400 78v184l-45 5V152l-45 83-47-83v129l-53 7V52l57 8 43 83 43-70z"/>
<path class="middleman-logo__bottom-left-bar" fill-opacity=".45" d="M0 300l200 40v-30L0 280z"/>
<path class="middleman-logo__bottom-right-bar" fill="#fff" d="M200 340l200-40v-20l-200 30z"/>
</svg>
<h1>
Middleman is Running
</h1>
<%= link_to(
"Read Documentation",
"https://middlemanapp.com/basics/templating_language/",
target: "_blank"
) %>
The first thing we see in this file is the data set up top for the title. This
is optional and you aren't required to use data fields if you aren't comfortable
with them. Next up is the content of our page, just an SVG and a heading. We
end with a link_to call, which just generates a link. Again, if you'd prefer
to just stick with html syntax you absolutely can, though if you've used Rails
before then you'll be familiar with this function.
Let's make some changes to their basic layout, and bring in the defaults we've
worked up so far in the HTML & CSS topic. First we'll replace their layout with
our basic page, and I'll go ahead and drop normalize, type base and a style css
files into the stylesheets folder.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><%= current_page.data.title || "Middleman" %></title>
<%= stylesheet_link_tag "normalize" %>
<%= stylesheet_link_tag "typebase" %>
<%= stylesheet_link_tag "style" %>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<%= yield %>
<footer>
<p>
<%= current_page.data.footer || "Some random copyright" %>
</p>
</footer>
</body>
</html>
We can also swap out the contents of our index.html.erb file with one we
previously built:
---
title: Hello world, from Middleman
footer: There is some footer info here
---
<header>
<h1>
<%= current_page.data.title %>
</h1>
</header>
<div class="content">
<menu>
<ul>
<li><a href="#">Foo</a></li>
<li><a href="#">Bar</a></li>
<li><a href="#">Baz</a></li>
</ul>
</menu>
<aside>
<p>
<!-- SNIP Lorem -->
</p>
</aside>
<main>
<p>
<!-- SNIP Lorem -->
</p>
<p>
<!-- SNIP Lorem -->
</p>
<p>
<!-- SNIP Lorem -->
</p>
</main>
</div> <!-- content -->
I set two pieces of data up top. One for the header and one for the footer.
These have both been rendered in the layout, as well the heading one in the h1
tag on the page. Setting data up top and using it inside of the page is a common
pattern with Middleman, and is really convenient.
Finally let's rebuild our project:
$ middleman build
In looking at our index.html file we can see it all got updated properly, we
built our first page with Middleman!
Today we looked at the basics of Middleman for building static sites. We explored how to install the framework and its basic file structure. We then saw how to build a site into static files, and looked briefly at ERB as a templating language. We then imported some previous pages we wrote into their basic setup, played with data, and rebuilt a static version of our page via Middleman.
Middleman is a great project, so we'll explore it more in the future as we start to look at SASS and HAML to make writing CSS and HTML more efficient. See you next time!