April 7, 2021

Rails unpacked: tailwindcss without webpack

I'm no fan of webpack and Rails' attempt to integrate it using the webpacker gem. I try to get tailwindcss running using DHH's tailwindcss-rails gem on a new webpack(er)-less Rails app.

Rails unpacked: tailwindcss without webpack

If you like webpack(er) or are willing to cope with it, good for you. I guess it's safe to say, it's not for me. Strong feelings aside, I was curious if the time has come for me to get rid of it for good.

Here is what I'm trying to cover in this and upcoming posts:

  • set up a new Rails app without webpacker
  • try to get TailwindCSS and
  • StimulusJS working
  • probably throw in TURBO too, because I meant to test drive it since it came out

I'm not going to go into why webpack is not my friend. Life's too short.

rails new

I'm going to use the latest Rails 6.1 release running on Ruby 3.0. I'm using asdf with the asdf-ruby plugin to manage my Ruby versions:

# Create a directory for the app
> mkdir playground
> cd playground

# Configure the ruby-version to use
> echo "3.0.0" > .ruby-version

# Make sure the Ruby version is installed
> asdf install
basic setup

Now it's time for creating a new Rails app. Rails comes with webpacker by default. There is no way to tell it to leave webpacker out and set up the asset pipeline for javascript instead.

What I'm going to do is to tell Rails to leave out the javascript setup altogether.
Once we add stimulus-rails or hotwire-rails (which includes stimulus-rails), those gems will take care of setting up javascript using the asset pipeline.

# Install rails
> gem install rails

# Create a new rails app, without webpacker. Oooh! Exciting!
> rails new . -d postgresql --skip-turbolinks --skip-jbuilder --skip-javascript

# once that's done run
> bin/setup
create a new rails app

At this point we've an empty Rails app working. Time to add some life to it by adding a model and controller:

# Let rails generate a "Tweet" scaffold. Skipping stylesheets because we'll add tailwindcss shortly
> bin/rails g scaffold tweets body:text --no-stylesheets

> bin/rails db:migrate

# now take it for a spin
> bin/rails s
create a "Tweet" scaffold
Ain't it a beauty?

tailwindcss

I'm still trying to find out if I like or loathe tailwindcss. I love it's documentation and its makers are gifted creators and artists. It's beautiful on many levels, and I want to be a fan.
I'm not so sure if I like inline styles though. Yep, said it, that's what it is. Declaring bankruptcy on separation of concerns and throwing your markup and styles into the blender and hoping for the best.
But it starts to grow on me. And I like me a good blender.

Now let's find out if it will blend using Rails' asset pipeline instead of webpack(er).

> bin/bundle add tailwindcss-rails

> bin/rails tailwindcss:install
add and install tailwindcss-rails

The tailwindcss-rails gem will detect if webpacker is present or not. If it doesn't find webpacker, it will set itself up using Rails' asset pipeline.

With tailwindcss ready to go, I added some basic styling:

Having tailwindcss working without needing to deal with installing nodejs, and dealing with npm/yarn and webpack(er) is really nice.

But ... you probably guessed it: there are some caveats:

No customization

While tailwindcss does not need webpack at all, it is best installed as a PostCSS plugin. PostCSS is "a tool for transforming CSS with JavaScript". PostCSS can be run using a build tool like webpack, but could also be used stand-alone.
Anyway, you are going to need PostCSS (and nodejs) to customize your tailwindcss build in any way. If you want to add colors or enable variants using tailwindcss-rails just doesn't cut it.

Experimental

tailwindcss-rails is a really interesting experiment. And it's one that works surprisingly well.
The gem comes with a custom built CSS purger that mimics what PurgeCSS would do when building tailwindCSS with PostCSS.
Purging is the process of slimming down the full tailwindCSS build to just the CSS classes you are actually using in your app.
While the custom ruby implementation seems to do it's job, it's probably nowhere near the qualtiy of a battle-tested, mature tool like PurgeCSS.

Bottom line: there are going to be unexpected issues when using experimental code.

Slow...ish

Don't get me wrong, it's probably still better and faster than using it with webpack(er), but including the tailwindcss-rails gem in the Gemfile slowed down rails test:all runs from about 6s to around 34s. That's quite staggering.

An "unpurged" full build of tailwindCSS that gets used during development and testing is quite large. That's most probably true for when using it with webpack, too.
Same as with customization you are missing out on new features aimed at speeding up development like the awesome new "JIT" mode.

tl;dr

Yes, you can get tailwindcss working with Rails without webpacker.

And yes, it's awesome not having to deal with nodejs and npm and all that cruft when just trying to style your app with CSS.

But it's probably not ready for primetime. At least not in it's current iteration.

I've not given up on my quest to get it running without a full-blown webpack(er) setup, though. I plan to try an alternative approach using PostCSS CLI. Stay tuned.


The code for this post can be found on GitHub:
https://github.com/wolfgangrittner/playground/tree/rails-unpacked/tailwindcss-rails