Use Tailwind CSS v2.0 with Rails
Tags: rails, tailwindcss, css
Published: 2021-01-23 19:26:56

Recently, the folks behind Tailwind CSS released v2.0 🎉🎉
(Well, that was in November 2020, but hey did time even exist in 2020?!)

Checkout the [release notes](https://blog.tailwindcss.com/tailwindcss-v2)

But unfortunately when you try to add it to your Rails project, Webpack throws the following error (I am assuming you have already setup [@rails/webpacker](https://github.com/rails/webpacker) in your project):
![Error: Tailwind requires PostCSS 8](https://dev-to-uploads.s3.amazonaws.com/i/kc6fuygvnohf60ynwzoz.png)
```
Error: PostCSS plugin tailwindcss requires PostCSS 8.
```

The error message is simply saying that Tailwind v2 depends on PostCSS 8, however the current builds of webpacker use PostCSS 7. To fix this issue we can take one of two approaches:

## Easy Method
Well, Tailwind maintainers realized that PostCSS 8, being a recent release itself, is not very widely supported by popular frameworks like Rails. So, they were kind enough to release a [PostCSS 7 compatible build](https://tailwindcss.com/docs/installation#post-css-7-compatibility-build) for the time being.

All you have to do is
```
yarn remove tailwindcss
yarn add tailwindcss@npm:@tailwindcss/postcss7-compat
```
...aaand done!!

The compatibility build supports all of the features as that of the "normal" build. Awesome! Except for one catch though:

If you are working on a decently-sized project, the chances of the Rails version in your application being upgraded anytime soon may be low. And it is probable that the subsequent releases of Tailwind might not come with a compatibility build. So what do we do?

## (not-so) Hard Method
Well, won't it be better if we could just bump the PostCSS version in our Rails app? That way we won't have to depend on or worry about a compatibility build.
Let's try
```
yarn add tailwindcss@^2.0.2 postcss@^8.2.4
./bin/webpack-dev-server
```

Hmm, same error message? Oh yes, we should also upgrade postcss-loader
```error
yarn add postcss-loader@^4.2.0
./bin/webpack-dev-server
```
Another error message!!
![Error: Invalid options passed to postcss-loader](https://dev-to-uploads.s3.amazonaws.com/i/0ja19uw293jcfi9j00f6.png)
```
ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'config'. These properties are valid:
   object { postcssOptions?, execute?, sourceMap?, implementation? }
```
Here webpack is complaining that postcss-loader was initialized with an invalid option `config`. In older versions of the loader, `config` was used to pass PostCSS configuration option. From the error message above, you can probably guess that it has been renamed to `postcssOptions`. "Dang! I have to edit webpack config now!" was my reaction, but turns out it's not that difficult.
If you look at the contents of your `config/webpack/environment.js` file, it will look something like this:
```javascript
const { environment } = require('@rails/webpacker')

module.exports = environment
```

We change it to remove the `config` key from postcss-loader options for each file type (css, sass, moduleCss, etc.):
```javascript
const { environment } = require("@rails/webpacker");

environment.loaders
  .map((rule) => rule.value.use)
  .flat()
  .filter(({ loader }) => loader === "postcss-loader")
  .forEach((item) => {
    if (item.options) {
      item.options.postcssOptions = { from: item.options.config.path };
      delete item.options.config;
    }
  });

module.exports = environment;
```
Done!! Now webpack should compile your bundle just fine.