Not a subscriber?

Join thousands of others who are building self-directed lives through creativity, grit, and digital strategy—breaking free from the 9–5.
Receive one free message a week

HowTo: Setup Tailwind CSS 3 with Middleman

This post explains how I created the Tailwind CSS 3 + Middleman integration that is available on GitHub.


Download the source or fork the repository here.

Middleman is a Ruby static site generator that makes it easy to create custom static sites with the Ruby language (as well as ERB, etc).

The reason why I’m using Middleman over another static site generator is because I build my apps in Ruby on Rails and Middleman supports a very similar syntax with the view template language as well as development language. This allows me to have less context switching when I’m either working on the marketing site (a static site usually) or my fully blown SaaS app. In other words, I’m using Ruby on my SaaS app as well

To get started with Tailwind CSS 3 and Middleman 4 you’ll want t do the following:

Setup Middleman

Here’s how to set up Middleman …

Install the gem:

gem install middleman

Then initialize a project:

middleman init project

Now try to build and run your middleman app:

middleman build && middleman serve

You might get this error with Middleman:

TypeError: Cannot read property 'version' of undefined

If you get that error, update the middleman-autoprefixer gem to the following

gem 'middleman-autoprefixer', '~> 3.0'

in your Gemfile. This will fix the TypeError above.

Build and start your middleman site. You should be good to go.

Setting up Tailwind CSS 3 with the Tailwind CSS CLI

Install Tailwind CSS by running the following:

npm install -D tailwindcss
npx tailwindcss init

This will generate a tailwind.config.js file.

Open the .gitignore file, add node_modules/ and dist/ to it, so that the node_modules/ folder is ignored. We will talk about the dist/ folder below.

Open the tailwind.config.js file and change the contents to this:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./source/**/*.{html,erb}"
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

This will tell the Tailwind CSS CLI to watch for content changes in any of the html or erb files. If a change is detected, then Tailwind CSS CLI will recompile (when not in build mode).

Rename the source/stylesheets/site.css.scss to source/stylesheets/site.css

Open that site.css file and replace the contents with the following:

@tailwind base;
@tailwind components;
@tailwind utilities;

Open the config.rb file and add an external_pipeline for Tailwind

activate :external_pipeline,
  name: :tailwind,
  command: "npx tailwindcss -i ./source/stylesheets/site.css -o ./dist/stylesheets/site.css #{"--watch" unless build?}",
  latency: 2,
  source: "./dist/"

Lets break this down …

This external_pipeline tells Middleman to run a command upon build/serve.

The name: symbol is the name of the external pipeline that you give it. You can call this George or Fido, or Hotdog, middleman doesn’t care. It’s just for you to use.

The command:

npx tailwindcss -i ./source/stylesheets/site.css -o ./dist/stylesheets/site.css #{"--watch" unless build?}

Will compile the site.css file into its fully fleshed out css output in the ./dist/ folder.

Note the #{"--watch" unless build?} string interpolation at the end.

This tells Tailwind CLI to “watch” for any file changes that match the content block in the tailwind.config.js file. This will ONLY be added to the command if Middleman is NOT in a build (middleman build). If you run middleman serve the build? property will be false, therefore --watch will be added to the command. When --watch is present, Tailwind CLI will watch for file changes and automatically recompile.

Next we have the latency, this just tells Middleman how much latency between checking for new changes. Default is 0.25, which will work, I just changed this to 2 so it’s less chatty. You can play with this and set it to something you’d like. Under the hood Middleman uses the listen gem, check out that for more info on latency.

The source: symbol will tell Middleman the path to merge into the middleman build. Since Tailwind CLI is output its contents into the ./dist folder the entire contents will be merged into the file site. This folder doesn’t need to be checked into source control, this is why it was added to the .gitignore file.

That’s it.

Building and Running the Middleman App

Now run middleman build and you’ll see the files being built. You should be able to open the ./build/stylesheets/site.css and see the Tailwind CSS in that file.

If you run middleman serve the site will be served up locally.

Adjusting the i,ndex.html to use Tailwind CSS for Styling

If you look at the build/stylesheets/site.css you’ll notice that it does not have any utility classes in it.

I’ll be honest, this confused me for a bit and I thought I did something wrong.

Nope, thats expected!

In fact, if you look at the browser when running middleman serve the page will not look good as the styles in the index.html.erb file are not correct.

Tailwind CLI will read your files (as defined in the content block) of the tailwind.config.js file. At this point, Tailwind CLI has not seen ANY utility classes used in any of the matching files so no utility classes were included in the output.

I’ve changed the index.html.erb file to this, notice the Tailwind CSS utility classes that are applied:

---
title: Welcome to Middleman
---

<div class="flex flex-col min-h-screen justify-center items-center">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 340" class="w-32 fill-current" 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 class="text-2xl">
    Middleman is Running
  </h1>
  <%= link_to(
  "Read Documentation",
  "https://middlemanapp.com/basics/templating_language/",
  target: "_blank"
) %>

</div>

Now run middleman serve (or build) and look at the build/stylesheets/site.css file. You’ll notice that has a handful of utility classes at the bottom of the file. These are the classes that your app us using. As you add new classes and rebuild the app (or just have serve running with the --watch flag).

Thats it, I hope that helps explain the process of how this was built.

Download the source for the template here.