thoughts on code


Zen Middleman 4 Setup with Brunch and Bower

As a developer, I’m a huge fan of static websites. They are reliable, fast, and SEO-friendly. I also learned to love creating static websites by using tools like Middleman. In this post, I won’t try to convince you on why Middleman is great (maybe another day). Instead, I’ll be focusing on how to setup a Middleman 4 project that leverages best-practice front-end build tool and package management in tandem.

Before Middleman 4, using tools like Bower, Brunch, and Gulp always felt like more work than it was worth. Middleman was optimized for using Rails’ Sprockets to manage front-end assets and gems to handle dependencies (e.g. Sass, Babel, and React). The issue, however, was that many of these gems were infrequently updated and provided inconsistent API’s for integration with your project. If you’re familiar with front-end best practices, using tools like Bower to manage dependencies and Brunch (or Gulp, Broccoli, Webpack) for compilation should be a no-brainer. So how can we do that with Middleman?

Fear no more! In Middleman 4, the developer can choose to use an external build pipeline. Middleman makes no assumptions about what tools you prefer. Simpy tell it to activate the external pipeline, what command to run on server start, and where to look for the compiled assets. Could it really be that simple? Yep! Take a look at the actual code needed to set it up:

activate :external_pipeline,
  name: :brunch,
  command: build? ? 'npm run prod' : 'npm start',
  source: "./public",
  latency: 1

We tell Middleman that we’d like to use an external pipeline for our assets, use different build commands based on whether we’re building the project for production, and to look for the final output in the ./public folder.

Middleman’s job is dramatically simpler here. Instead of worrying about using Sprockets to compile assets, it simply looks for the corresponding CSS and Javascript files in the public folder. In my case, they are site.css and site.js respectively.

Why Brunch?

Honestly, you can use whatever tool you’re comfortable with. With how fragmented the Javascript community is, there really isn’t an answer for the “best tool.” The reason I chose Brunch was for its simplicity. With the exception of Webpack, I’ve done projects in pretty much all the popular front-end build tools. Brunch stood out to me for its simplicity, but it’s by no means the only choice. Our main goal is to select a tool that complements Middleman, not overtake it. It should be simple to set up, easy to configure, and get the job done. Brunch does exactly that.

To add functionalities to Brunch, simply npm install the corresponding packages. Here are the packages I’m using for this site:

"devDependencies": {
  "sass-brunch": "^2.6.2",
  "auto-reload-brunch": "^2.0.0",
  "babel-brunch": "~6.0.0",
  "babel-preset-es2015": "~6.3.13",
  "brunch": "^2.4.0",
  "clean-css-brunch": "^2.0.0",
  "css-brunch": "^2.0.0",
  "javascript-brunch": "^2.0.0",
  "uglify-js-brunch": "^2.0.0"
}

These packages gives me the ability to use Sass and Babel as well as help me minify/uglify my CSS/Javascript files.

So now that we have the necessary packages, how do we use them? Enter brunch-config.js. This is the file Brunch looks for to figure out how to do its job. Here is the brunch-config.js file I’m using for this site:

module.exports = {
  // Where your source asset files live
  paths: {
    watched: ['source/assets']
  },
  conventions: {
    assets() { return false; }
  },
  files: {
    stylesheets: {
      joinTo: 'assets/stylesheets/site.css'
    },
    javascripts: {
      joinTo: {
        'assets/javascripts/site.js': 'source/assets/javascripts/site.js',
        // bundle all JS files from Bower packages into `vendor.js`
        'assets/javascripts/vendor.js': /^(bower_components|vendor)/
      }
    }
  },
  modules: {
    wrapper: false
  },
  plugins: {
    babel: { presets: ['es2015'] },
    sass: {
      mode: 'native',
      options: {
        // include any Sass files from outside of the `source` folder, such as from Bower packages
        includePaths: [
          'bower_components/normalize-scss/sass',
          'bower_components/bourbon/app/assets/stylesheets',
          'bower_components/foundation-sites/scss'
        ]
      }
    }
  }
};

A bit overwhelming? No worries, I’ll walk you through the important bits.

  • The paths keys tells Brunch where to look for the source files so it knows to watch them for changes.
  • The files key tells Brunch where to find the source CSS and Javascript and where to store the compiled code.
  • The plugins key enables and configures your Brunch plugins. In the case, I’m using Babel and Sass. The Sass plugin also allows you to include Sass files that are outside of your watched directories.

I won’t walk through every line of this file here. If you’re interested in learning more, take a look at the docs here. Brunch has a healthy plugin ecosystem as well–make sure to check out their plugins page.

Using Bower with Brunch

There are a couple of ways to import the Bower Javascript and CSS (Sass in my case) files. For Sass files, I use the Sass Brunch plugin to cherry-pick the Sass files I want to include with the includePaths key.

For Javascript, I use this line:
'assets/javascripts/vendor.js': /^(bower_components|vendor)/

It specifies where to find the JS files (./bower_components), and where to bundle them into (assets/javascripts/vendor.js). Now that I have a vendor.js file, I can simply include it in my layout.html.erb file in Middleman with <%= javascript_include_tag :vendor %>.

Gotcha’s

Brunch output path must match where we set the assets directories in config.rb. For this site, I’ve set it to source/assets/** with:

set :js_dir, 'assets/javascripts'
set :css_dir, 'assets/stylesheets'
set :images_dir, 'assets/images'
set :fonts_dir, 'assets/fonts'

Hence I have Brunch compiling all bundled files to the ./public/assets/ folder.

You’re done

That’s all you need! With this setup, we let the front-end build tool do its job so Middleman can focus on managing the site content. Remember that it really doesn’t matter what front-end build tools you use, the important thing is that it does what you need it to do. I’ve done a similar setup with Gulp before, which also worked out great. If you want to take a closer look at my setup, the source code is on GitHub.

I’m a big fan of Middleman and I plan to write more about it in the future. In the meantime, take a look at my SEO optimized Middleman template.

Got questions or feedback? Tweet me at @feifanw.


Next Article

Zen static site hosting with GitHub Pages, Middleman, and CloudFlare

I love static sites. They are fast, reliable, and SEO-friendly. I’m an avid user of Middleman, which is a Ruby-based static site generator. I have a fantastic Middleman workflow, but what about deployment and hosting?

When it comes to hosting provider, there are a few requirements from my end:

  • Easy to deploy
  • CDN-enabled
  • Reliable
  • Free or almost...

Continue reading