Switching to Middleman

I just switched my homepage from Jekyll to Middleman. The frameworks are very similar and the migration has been relatively painless. The following notes recap the motivations for the switch and what I had to to move to the new framework.

Remark. The following notes were written when I was using older versions of both frameworks, namely, Middleman 3 and Jekyll 2. Some of the remarks are still valid, others issues are now less relevant. I updated the post to reflect some of these changes, but some caution still has to be applied.

Motivation

The main strengths of Middleman are, in my opinion:

  • Support for erb templates. Middleman allows one to use Ruby rather than Liquid for “dynamic” content. On top of a more familiar syntax, which makes the construction of dynamic content simpler and more flexible (for me, at least), this feature allowed me to reuse a template I developed for a Rails application.
  • Generation of individual pages from data using the proxy directive. Although I have not yet used this feature, doing the same trick in (older versions of) Jekyll requires the use of plugins. One of such plugins is Jekyll datapage generator
  • Support for the asset pipeline and cache buster This has been further improved in Middleman 4.
  • Simpler deployment. A Middleman extension supports deployment via rsync or ftp. To achieve the same trick with Jekyll I had to define a Rakefile, which is available here: Jekyll Rakefile.
  • The build command does not regenerate files which have not been changed. This comes at the cost of a slower compilation, but it can make deployment a lot more efficient, if you care to look at the creation dates of files.
  • Simpler support for helpers. Middleman support helpers written in Ruby. This makes their development easier for me. The same trick in Jekyll requires to register a new Liquid filter and ends up in more code and more difficulties in managing multiple arguments.
  • Support for multiple blogs. This is a feature Jekyll also has. The main difference is that Middleman’s blog extension has commands to generate articles and allows one to keep posts’ assets together with the posts.
  • Access to sitemap and resources. The access to the sitemap and to resources (e.g., page content, page metadata) is well documented.

Various other features of Middleman are similar to those Jekyll provides: support for data, support for Yaml frontmatter, partials, nested layouts.

The only issue I have found with Middleman is an incompatibility between the Sass release of Foundation 5.4.7 and the compass library required by Middleman. This is, in fact, more a problem with Foundation than with Middleman. The effect on websites based on Foundation is that changes to the default configuration are ignored. I have not yet found a good workaround and I’ll just wait for Foundation to release a version which supports more recent releases of Compass (most likely: Foundation version 5.5).

Technical steps

These are the main steps to migrate an existing Jekyll website to Middleman.

Phase 1. Website up and running with no layouts:

  1. Create an empty project with middleman init
  2. Move the Jekyll sources to the source directory
  3. Rename each file to specify the chain of transformations you want Middleman to perform. For instance: index.textile should be renamed index.html.textile. If you want also want to use ERB in the file, add the erb suffix; e.g., rename the file to index.html.textile.erb
  4. Change all Liquid markup to the corresponding erb code
  5. Replace includes with partials
  6. Optionally, use link_to and the other helpers (e.g., image_tag, to simplify the way in which assets are referenced)

The steps above should be enough for a basic website. If you are using custom layouts, move to the next phase!

Phase 2. Migrate layouts and take advantage of Middleman features:

  1. Move the Jekyll directory _layouts to sources/layouts and change the extension of the layouts to erb. Thus, for instance, _layouts/default.html becomes sources/layouts/default.erb
  2. Migrate all the Liquid markup to erb (including <%= yield %> in place of `<div class="container grid-lg">

</header>

<div class="columns">
    <div class="column">
        <h1>Source Code in Org Mode</h1>
        <p>To enable execution of ruby code in OrgMode files, put in your <code class="highlighter-rouge">.emacs</code> file</p>
(require 'ob-ruby)

You can then insert ruby code in your org file using the following tags:

#+BEGIN_SRC ruby
  a = 2 + 3
  b = 10 * 2
  [a + b, a]
#+END_SRC

Evaluate with C-c C-C … and voila, the result is shown in the buffer

#+RESULTS:
| 25 | 5 |

Consult the org-mode manual for more information.

    </div>
</div>

<div class="columns">
    <div class="column">
    <p><strong>Get in touch</strong></p>
<textarea id="body" name="body" class="form-input" required rows=1 placeholder="Start the discussion"></textarea>
    </div>
</div>
<div class="columns">
    <div class="column">
        <p><strong>Comments</strong></p>
    </div>
</div>

</div>

`

  1. Use stylesheet_include_tag and javascript_include_tag to include stylesheets. Use the require directives in the javascripts and stylesheets assets to compose your assets. This is the same of what Rails does and it is well documented on the Middleman website
  2. If you are using nested layouts, you need to use the wrap_layout syntax (Have a look at: https://middlemanapp.com/basics/templates/)

Phase 3. Activate some specific features:

  1. Modify the Gemfile to include the extensions you prefer (e.g., middleman-blog and middleman-deploy)
  2. Modify config.rb to minify and compress assets, to bust cache, etc.

These steps are very well documented and there is no need to copy them here. Have a look at, for instance, Blogging and Build and Deploy.

Deployment on a sub-Uri

This section has been superseded:

  • Middleman 4 now supports :assets_hosts (Asset Hosts).
  • Jekyll now has a base_url variable, which can be set from the command line, simplifying the generation of absolute URLs.

One critical point (both with Jekyll and Middleman) used to be, the management of URLs, especially if the website is deployed on a suburi (e.g., http://www.example.com/a/b/c/). The problem is the way in which URLs are interpreted. More in details:

  • Using relative URLs (href="x/y/z") in templates or in pages is no good, because pages might be deployed at different levels of depth on the website, making relative references wrong
  • Using absolute URLs (href="/x/y/z") won’t work, unless you specify the full path (e.g., /a/b/c/). This however, breaks the possibility of previewing on the local webserver and makes re-deployment on a different URL more difficult.
  • Similar to the previous point, using fully qualified names (href="http://...") breaks the possibility of previewing on the local webserver and of moving your website to a different location, if needed.

To solve this problem, when I started using Jekyll, I defined a Rakefile to simplify the management of common Jekyll operations, including deployment. The Rakefile sets a variable site.url in _config.yml. The variable can thus be prepended to all URLs used on a website, to make them absolute.

Middleman supports a simpler solution. More in details, the :http_prefix variable can be used to prepend a portion of a path to all URLs defined with the standard helpers: link_to and image_tag, stylesheet_include_tag, javascript_include_tag.

Thus, for instance, if the website lives on “http://www.example.com/a/b/c/”, it is sufficient to set :http_prefix in config.rb:

configure :build do
  set :http_prefix, "/a/b/c/"
end

and Middleman will take care of replacing, e.g., <%= link_to "p.html" %> with <a href="/a/b/c/p.html">. (Notice that settting :http_prefix to a full URL, like, e.g., http://..., will cause an error.)

The problem remains, however, with links defined using the native markup tags. For instance, Middleman will not replace the URL of links written in Textile (or Markdown).

The problem can be solved by defining a helper to generate absolute URLs. Add to your config.rb the following code:

helpers do
  def aurl url
    File.join(http_prefix, url)
  end
end

configure :development do
  set :http_prefix, "/"
end

configure :build do 
  set :http_prefix, "/a/b/c/"
end

and use the aurl helper every time you want to insert a link or a path using the markup of the templating language. For instance:

  "Some link on my website":<%= aurl("some_page.html") %>

More in details, the following rules apply:

  • If you are using one of the tags of the markup languages, always use aurl
  • If you are using image_tag you are fine
  • If you are using link_to you are fine

Get in touch

Comments