Rebecca Le

@sevenseacat

One neat trick to getting Tailwind's JIT compiler working in Phoenix

May 21, 2021

Written using Phoenix 1.5 and Tailwind 2.1

Note: This does not work on Windows machines. I'm sorry, Windows users!

I'm a big fan of Tailwind CSS for styling the user interfaces of my web applications. (This site is styled with Tailwind!) Recently it received an awesome update that added JIT compilation support. This has a couple of amazing benefits:

This is all great! There's one trick to getting it working in your Phoenix applications though.

If your app is already using Tailwind, setting up the new JIT compiler is easy - you just need to add mode: "jit" as a config option in assets/tailwind.config.js. But you also need to be running your asset compiler with the NODE_ENV env variable set to development, so Tailwind will start up its own watcher to watch your templates and update your CSS accordingly.

(If your app isn't yet using Tailwind, this guide by Mike Clark is great for getting it all installed and working.)

Phoenix is configured to run Webpack via a watcher specified in your config/dev.exs file. By default, it looks something like this:

# config/dev.exs

config :your_app, YourAppWeb.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
cd: Path.expand("../assets", __DIR__)
]
]

So it starts up a Webpack process by running node node_modules/webpack/bin/webpack.js --mode development --watch-stdin. And there's nowhere to specify the NODE_ENV. Drat.

However, we can change this watcher to use a different script. In your assets/package.json, there's already a script set up to run Webpack in a development environment, called watch - and we can use this for our watcher instead.

If you're using npm for your JavaScript package management, you can replace the watcher with this:

watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
npm: [
"run",
"watch",
cd: Path.expand("../assets", __DIR__)
]

And if you're using yarn, it's even simpler:

watchers: [
node: [
"node_modules/webpack/bin/webpack.js",
"--mode",
"development",
"--watch-stdin",
yarn: [
"watch",
cd: Path.expand("../assets", __DIR__)
]

Then you can edit the watch script listed in assets/package.json to add the NODE_ENV definition.

{
"repository": {},
"description": " ",
"license": "MIT",
"scripts": {
"deploy": "webpack --mode production",
"watch": "webpack --mode development --watch"
"watch": "NODE_ENV=development webpack --mode development --watch"
},
...

And you're done! If you start up your Phoenix server now with mix phx.server, you should get the warning about using JIT because it's so new and prone to change, and your CSS should be lean and mean. Edit a template and use some different Tailwind classes, and your CSS will automatically recompile, LiveReload will do its thing, and you'll immediately see the changes in your browser.

✨ Perfection. ✨

(I've set up a GitHub repository with some proof-of-concept code getting this working - you can check it out here.)

These changes have been suggested several times to the Phoenix core team before (and again by myself just today because I was unaware of the history). However, because they don't work correctly for Windows users, they can't be accepted into the Phoenix core repository. If you have access to a Windows machine, see if this kind of change works for you, or if you can make it work, and contribute it back! It would make life nicer for everyone :)

(Thanks to Robert Ellen for proofreading and catching some of my typos!)

← Home

Want to talk tech on Twitter? You can find me at @sevenseacat!

Built using 11ty and TailwindCSS.