Tailwind CSS with Rails 6 and Webpacker
I don’t do many things frontend these days, but I’ve wanted to try out Tailwind for a while, and I finally had the opportunity. Alas, it was a Rails app which had no frontend at all (apart from administrate), so I need to start from the very beginning. Here’s how I did it:
Webpacker
I needed to add Webpacker, as I’d initially not done this when generating
the application. You should be able to skip this if you already have a working
setup. First, I added webpacker to the Gemfile and then ran the generator:
bundle exec rails webpacker:install
This command configures much of what’s needed. The Webpacker directory
layout ends up looking like this:
app/javascript
├── packs
│   └── application.js
└── src
packs contain the collection of functionality processed with Webpacker to
build the package of JavaScript (and CSS!) that serves your application. The
default one being application.js.
In app/javascript/packs/application.js, I have the following:
require("@rails/ujs").start()
require("turbolinks").start()
And then, in the application layout, we’ll add the two hooks required to get JavaScript and styles included:
<%= stylesheet_pack_tag "application", media: "all", "data-turbolinks-track": "reload" %>
<%= javascript_pack_tag "application", "data-turbolinks-track": "reload" %>
Which loads both the JavaScript application pack and the separated stylesheet.
These replace any existing stylesheet_link_tag/javascript_link_tag usage.
Tailwind CSS
Then, I added tailwindcss to the package.json using Yarn:
yarn add tailwindcss --dev
And generated a Tailwind CSS config file:
npx tailwindcss init app/javascript/src/tailwind.config.js
The configuration file starts empty and looks like this:
module.exports = {
  theme: {},
  variants: {},
  plugins: [],
}
To setup Tailwind, I’m importing the suggested imports in
app/javascript/css/application.css:
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
Webpacker is using postcss-import, so here I’m not using @tailwind to pull
in the dependency as suggested in the documentation.
To configure PostCSS, I needed to add Tailwind in the right place (and overwrite the default location it loads the config file from):
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('postcss-import'),
    require('tailwindcss')('./app/javascript/src/tailwind.config.js'),
    require('postcss-flexbugs-fixes'),
    require('postcss-preset-env')({
      autoprefixer: {
        flexbox: 'no-2009',
      },
      stage: 3,
    }),
  ],
};
Finally, I needed to configure Webpacker to expose a standalone CSS file for
every environment in the default section of config/webpacker.yml:
# Extract and emit a css file
extract_css: true
(You can also to delete the same line overridden in production.)
Asset management in Rails is gradually moving towards Webpacker, and this is probably a good thing — standardising around the most common tools used in the JavaScript community. But it’s still a bit confusing if this isn’t something do you often.