Artist’s impression of two neutron stars merging and exploding as a kilonova edited to have the Rails and TailwindCSS logos overlaid on the neutron stars. Original image University of Warwick/Mark Garlick

Adding TailwindCSS To A New Rails App

Published in Programming on

Working on a new side project, there's only one tool I'm going to reach for all of my design needs: TailwindCSS.

TailwindCSS is what I used to style v3 of this blog, and it's what finally made styling web pages accessible for me. Before Tailwind, the closest I'd get to front-end design was writing API endpoints.

Who's This For?

Are you working with a Rails 6.1 (possibly 6) application? Is it brand new, or at least not doing anything with alternative styling frameworks like Bootstrap? Then you might have found what you need! 😎

Going Off The Rails

Train accident

Image by jan baars from Pixabay

The TailwindCSS documentation is excellent, so before searching for any other posts about configuring it with a Rails application, I go straight to source.

Unfortunately, I don't have a great understanding of the Webpacker/JS dependencies in a fresh Rails app. When I ran through the standard install process, I didn't know Webpacker locked PostCSS to v7.

Guess what that means?

$ ./bin/webpack-dev-server
ℹ 「wds」: Project is running at http://localhost:3035/
ℹ 「wds」: webpack output is served from /packs/
ℹ 「wds」: Content not from webpack is served from /home/username/appname/public/packs
ℹ 「wds」: 404s will fallback to /index.html
✖ 「wdm」: Hash: 0370e0aaf225e03ead0d
Version: webpack 4.46.0
Time: 4571ms
Built at: 03/12/2021 9:50:39 PM
                                     Asset       Size       Chunks                         Chunk Names
    js/application-78a51a641bfdc9fa97d1.js    645 KiB  application  [emitted] [immutable]  application
js/application-78a51a641bfdc9fa97d1.js.map    690 KiB  application  [emitted] [dev]        application
                             manifest.json  364 bytes               [emitted]
ERROR in ./app/javascript/css/application.css (./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./app/javascript/css/application.css)
Module build failed (from ./node_modules/postcss-loader/src/index.js):
Error: PostCSS plugin tailwindcss requires PostCSS 8.
Migration guide for end-users:
https://github.com/postcss/postcss/wiki/PostCSS-8-for-end-users
    at Processor.normalize (/home/username/appname/node_modules/postcss-loader/node_modules/postcss/lib/processor.js:153:15)
    at new Processor (/home/username/appname/node_modules/postcss-loader/node_modules/postcss/lib/processor.js:56:25)
    at postcss (/home/username/appname/node_modules/postcss-loader/node_modules/postcss/lib/postcss.js:55:10)
    at /home/username/appname/node_modules/postcss-loader/src/index.js:140:12
ℹ 「wdm」: Failed to compile.

But of course, the TailwindCSS documents have that covered.

If you're integrating Tailwind with a tool that relies on an older version of PostCSS, you may see an error like this:

Error: PostCSS plugin tailwindcss requires PostCSS 8.

In this case, you should install the PostCSS 7 compatibility build instead.

This blurb is conveniently located immediately after the standard installation instructions. 🙌

Getting Back On Track

Photo by Gary Doughty on Unsplash

The only deviation from the official docs is Rails' use of Yarn instead of npm.

yarn add --dev tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

Then generate the TailwindCSS config by running the init command in the Rails app's root directory.

npx tailwindcss init

There will now (hopefully) be a tailwind.config.js file in the root directory. The default is fine for now, but the common Rails app paths need to be added to the PurgeCSS section. This is what my config file looks like after adding them.

module.exports = {
  purge: [
    "./app/**/*.html.erb",
    "./app/helpers/**/*.rb",
    "./app/javascript/**/*.js"
  ],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

The next step is creating an application.css file to import TailwindCSS into the app stylesheets. The name of the directory doesn't matter that much. Some instructions call it css, others stylesheets. I went with app/javascript/css/application.css, so that's how I'll reference it in the rest of the post. In that file, all you need to add is the imports for the framework's core.

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

To have Webpacker pick up application.css for processing, update app/javascript/packs/application.js to import it.

import "css/application"

PostCSS's config file (postcss.config.js) will also need tailwindcss and autoprefixer required. This should be the last config update before running webpack.

    require('tailwindcss'),
    require('autoprefixer')

In the layout file, typically app/views/layouts/application.html.erb, a stylesheet_pack_tag is needed, so the generated CSS file is included in the markup.

Add some styling to your layout or template files, then run ./bin/webpack-dev-server.

$ ./bin/webpack-dev-server
ℹ 「wds」: Project is running at http://localhost:3035/
ℹ 「wds」: webpack output is served from /packs/
ℹ 「wds」: Content not from webpack is served from /home/username/appname/public/packs
ℹ 「wds」: 404s will fallback to /index.html
ℹ 「wdm」: Hash: d66d265c9000c588a577
Version: webpack 4.46.0
Time: 12266ms
Built at: 03/12/2021 9:59:08 PM
                                     Asset       Size       Chunks                         Chunk Names
    js/application-27f9fc35a4c04a49ef48.js   5.57 MiB  application  [emitted] [immutable]  application
js/application-27f9fc35a4c04a49ef48.js.map   5.91 MiB  application  [emitted] [dev]        application
                             manifest.json  364 bytes               [emitted]
ℹ 「wdm」: Compiled successfully.

Finally, the journey to a beautiful application design can begin!

My designs still need “beautiful” in the scare quotes 😅

Did I miss anything? Was this helpful? @ me on Twitter and let me know!