Read more

Middleman configuration for Rails Developers

Dominik Schöler
May 26, 2017Software engineer at makandra GmbH

Middleman is a static page generator that brings many of the goodies that Rails developers are used to.

Illustration online protection

Rails professionals since 2007

Our laser focus on a single technology has made us a leader in this space. Need help?

  • We build a solid first version of your product
  • We train your development team
  • We rescue your project in trouble
Read more Show archive.org snapshot

Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.

Gemfile

Remove tzinfo-data and wdm unless you're on Windows. Add these gems:

gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!

gem 'bootstrap-sass' # If you want to use Bootstrap

gem 'byebug'

gem 'capistrano'
gem 'capistrano-middleman', require: false

config.rb

activate :livereload
activate :sprockets

configure :build do
  activate :minify_css
  activate :minify_javascript
  activate :asset_hash
end

# Middleman fails to reload helpers, although it notices their modification
# This force-reloads them
Dir['helpers/*'].each(&method(:load))

# Disable warnings
Haml::TempleEngine.disable_option_validator!

You might want to activate :directory_indexes. This tells Middleman to create Rails'ier URLs (/demo instead of /demo.html) with a little trick: It actually creates an index.html in a subdirectory (/demo/index.html). Your webserver (e.g. Apache) needs to support this.

Localization

For localization to work, you need to:

# config.rb
activate :i18n, mount_at_root: false, langs: %w[en de]

Any page inside source/localizable will be generated once for each locale in langs. mount_at_root is true by default, which would put files of the first locale (here: en) at the site root (e.g. /), and only prefix the non-default locales (e.g. /de/). Setting it to false prefixes all locales.

Note there is no localized path helper. You need to prefix link hrefs yourself (e.g. with a helper).

Helpers

Inside config.rb, you can define helpers in a helpers { ... } block. However, this does not scale very well. You're best off creating a /helpers directory and putting helper files there just like you know it from Rails. Reminder: Middleman brings the handy helper methods capture_html, content_tag and tag.

Environments

Middleman 4+ supports different environments. Think of them as config.rbs you put into environments, e.g. environments/staging.rb. They will only be evaluated when running middleman for the specific environment. Default for the local dev server is development, default for building is production. Activate an environment with -e staging or --environment=staging.

Test for environments like this:

environment? :staging

Testing

Complex "static" pages might need some integration testing, especially if they contain complex Javascript code. To employ Cucumber with Spreewald Show archive.org snapshot and Selenium, add these gems to the Gemfile:

group :test do
  gem 'cucumber'
  gem 'spreewald'

  gem 'capybara'
  gem 'selenium-webdriver' # Only for running tests in a real browser (suggested)
  gem 'capybara-screenshot' # Optionally

  gem 'rspec' # Dependency of Spreewald
end

Now run bundle exec cucumber --init and add this code to env.rb:

Bundler.require :default, :test # Require default + test gems from the Gemfile

require 'capybara/cucumber'
require 'spreewald/web_steps'

middleman_app = ::Middleman::Application.new do
  config[:environment] = :test
  
  # Note that :build mode is the right way to test, because in production
  # your site will be "built", too. However, testing in :build mode oddly
  # takes thrice as long as :server: mode, so you might try and skip this
  # setting for faster test runs.
  config[:mode] = :build
end
Capybara.app = ::Middleman::Rack.new(middleman_app).to_app

# Only when using Selenium (suggested): Run all tests in Chrome
Capybara.register_driver :selenium do |app|
  Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.default_driver = :selenium

You need the Google Chromedriver Show archive.org snapshot binary to use Chrome with Selenium.

Configure Capybara-Screenshot with this file:

# features/support/capybara_screenshot.rb

require 'capybara-screenshot/cucumber'

# Have HTML screenshot render with assets (while `middleman` is running)
Capybara.asset_host = 'http://localhost:4567'

module Capybara::Screenshot

  # Monkey-patch: Screenshot location
  def self.capybara_root
    File.join Dir.pwd, 'tmp', 'capybara_screenshot'
  end

end

Deployment

Run cap install STAGES=production,staging.

When you're deploying with Capistrano, you might need to set :build_dir, 'build/public' in config.rb. This will render the page into a public subdirectory, which your Rails'ish webserver is already configured to deliver from.

Note that you must not require capistrano-middleman manually, although stated in the gem's README. Doing so would screw the underlying Rake tasks.

If you want to use different environments for different deployment stages, add this to the stage files:

set :middleman_options, %w[--environment=<your chosen env>]
Dominik Schöler
May 26, 2017Software engineer at makandra GmbH
Posted by Dominik Schöler to makandra dev (2017-05-26 17:49)