Getting started with Middleman, Bower, Grunt & Sass

What is Middleman?

Middleman is a static site generator. The general idea is that you work on your local machine with a nice template based system using your favorite tools & workflow including live reloading, Bower, Sass, Less etc. Once you are satisfied with the result you create a build, a set of static html pages. Those pages are deployed (copied) to the server - done.

I found the approach interesting as you don't have any code online, but have the flexiblity to change things easily.

Preparation

We are going to use You can download the code used in this mini example here (the repo has a couple of branches for the different steps shown below):
git clone https://github.com/luebbert42/middleman-bower-grunt-sass-demo mysite

Step 1: create the initial project

gem install middleman
middleman init mysite

This will install middleman and create a new middleman project in the directory "mysite" with a couple of css files, folders for javascript and images and the main configuration file "config.rb". For now you don't have do change anything to get your new site up and running.

cd mysite
middleman server

Check the output of the last command, middleman will print the address of your new super awesome website, usually something like http://0.0.0.0:4567/ (depends on your network). Open this address in your browser.

W00t - you are a genius, aren't you?!

Wait, Middleman is a static site generator, where are the static pages? The preview server uses ruby and is for preview only. Let's create the static files next.
cd mysite
middleman build

Middleman will create a directory mysite/build with the static files. Right now this is not really interesting as you are not using any of the interesting features of middleman like the templating system or CSS preprocessing. Let's change that.

Step 2: Add bower

I like to use Bower to install 3rd party components like Jquery, Bootstrap, Foundation etc. In this tutorial I'll use Zurb Foundation as alternative to Twitter Bootstrap and install it via Bower as an example of how it works.

I plagiarized the directory structure I am using below from Mr Mighty Senior Frontdev Dinko Verži. Note that I moved the current content to the new middleman directory. The bower stuff is stored in "bower_components" at root level.

opinionated directory structure

In detail:
cd /path/to/my/project/mysite
mkdir middleman
mv source middleman
mv Gemfile* middleman/
mv config.rb middleman/
Init bower as usual
cd /path/to/my/project/mysite
bower init

Create a .bowerrc file in mysite/middleman/source/.bowerrc with the following content:


{
"directory" : "../bower_components"
}

Now let's install finally use bower to check if everything is working:

bower install foundation --save

The last command created a couple of new directories and files in the bower_components directory. Zurb Foundation uses Sass as preprocessor and we want that as well. Let's do that next.

Step 3: Add Grunt

I assume that you have Grunt already installed. Check the Grunt documentation if not. Create /mysite/package.json, here is how my package.json looks like. Note that I have included "grunt-middleman". Grunt-Middleman makes it possible to run middleman commands easily in Grunt tasks.


{
    "title": "mysite/package.json - MySite Super Awesome Demo Thingy",
    "description": "npms used for the grunt part of this demo",
    "version": "1.0.0",
    "private": true,
    "devDependencies": {
        "grunt": "~0.4.5",
        "grunt-contrib-copy": "^0.8.0",
        "grunt-contrib-jshint": "~0.10.0",
        "grunt-contrib-nodeunit": "~0.4.1",
        "grunt-contrib-sass": "^0.9.2",
        "grunt-contrib-watch": "^0.6.1",
        "grunt-middleman": "^0.2.0",
        "jit-grunt": "~0.9.1"
    }
}

Install the project dependencies with

npm install

Next we have define the tasks we want to automate. You can copy my Gruntfile.js as a starting point.

cd mysite
wget https://raw.githubusercontent.com/luebbert42/middleman-bower-grunt-sass-demo/master/Gruntfile.js

This is not a Grunt tutorial, but let me roughly explain what goes on in the Gruntfile. The Gruntfile defines a couple of tasks like "app-build", "app-serve", "app-watch" etc (look for "registerTask" in the code). Those tasks use Grunt npm modules, e.g. the app-watch task uses Grunt's Sass plugin. Grunt plugins often require some app-specific configuration. This is done in the large "initConfig" block at the beginning of the file.

The Gruntfile compiles three files, foundation.scss and normalize.scss come with Foundation Zurb, app.scss will be the place for the app-specific CSS rules. To keep things simple I am copiyng the SASS files from the bower component directory manually once and create an empty app.scss file to avoid error messages from Grunt.

cd mysite
mkdir -p middleman/source/sass
cp -rf bower_components/foundation/scss/* middleman/source/sass/
touch middleman/source/sass/app.scss

Now when you run

cd mysite
grunt

the default Grunt task is executed which is in our case a little overview of the defined tasks.

I have always (at least ;-)) two terminals open, in one I run the preview server, in the other one I run the watch task which automatically checks for changes in the file system and runs the sass preprocessor if necessary.

#terminal 1
cd mysite
grunt app-watch
#terminal 2
cd mysite
grunt app-serve

Adding livereload

Not bad, but we want it even more convenient. Let's add livereloading by adding three lines to mysite/middleman/config.rb.

# add to /mysite/middleman/config.rb, e.g. after "set :images_dir, 'images'"
  configure :development do
    activate :livereload
  end

Restart "app-watch" and "app-serve" and do some random changes e.g. to "mysite/middleman/index.html.erb" to test if is working.

Almost there: "hello world" with Zurb Foundation

Now we are - finally - able to use all the nice infrastructure/tools to do something awesome. Well, not really awesome in this example, but I am sure you will do something great ;-)

Here is how I adapted the default layout located in middleman/source/layouts/layout.erb to use Zurb Foundation. Note that I am referencing to the preprocessed css files located in my assets/css directory (I am including three css files separately instead of concatting them to simplify the example). "app.css" is my own custom css stuff.

  <!-- mysite/middleman/source/layouts/layout.erb -->
  <!DOCTYPE html>
  <!--[if IE 9]><html class="lt-ie10" lang="en" > <![endif]-->
  <html class="no-js" lang="en" >
      <head>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title><%= current_page.data.title || "MySite" %></title>

          <%= stylesheet_link_tag 'normalize.css' %>
          <%= stylesheet_link_tag 'foundation.css' %>
          <%= stylesheet_link_tag 'app.css' %>

          <%= javascript_include_tag  "all" %>
      </head>
  <body>
      <div class="row">
          <div class="large-9 columns" role="content">
              <article>
                  <%= yield %>
              </article>
          </div>
      </div>

      <script>
          $(document).foundation();
      </script>
  </body>
  </html>

As for Javascript I am only including "all.jss" . This file contains a list of the js files I need for my application. Notice that e.g. Jquery is required here which we installed using bower.


  /* /middleman/source/assets/js/all.js */
  //= require jquery/dist/jquery.min
  //= require modernizr/modernizr
  //= require foundation/js/foundation.min
  //= require_tree .
  $(document).ready(function() {
     App.init();
  });

The "require_tree" statement adds everything in the current directory as a requirement including "app.js". "app.js" holds my own custom app-related js code like the typical "onSubmit/onChange/onSomethingElse"-Listener Jquery voodoo.

 /* /middleman/source/assets/js/app.js */
var App = {
    init: function() {
       console.log("do some initial JS stuff here on page load");
    }
    // eventListeners etc. go here
};

Download source code

You can download the code used in this mini example here (the repo has a couple of branches for the different steps shown above):
git clone https://github.com/luebbert42/middleman-bower-grunt-sass-demo mysite

Other topics not covered yet

  • adding aditional path to config.rb
  • the template language (includes, if/then/else, partials...)
  • using data fixtures and proxies to create a set of similar pages (like /edit/1.htm, /edit/2.htm etc)
  • defining your own ruby helper functions
  • assigning different layouts
  • inspect variables for debug purposes
  • how to deploy, e.g. via rsync