Ember + Tailwind CSS + postcss-import

12 November 2019

For a long time, the standard way of making an npm package work in your Ember app was to install the "integrator" package and call it a day. However, since we have ember-auto-import, an alternative is to use the npm package directly – and possibly write some configuration code.

One benefit of using the package directly is that you get access to the lower-level primitives, including being able to configure it if you need to.

If you use an Ember-specific integrator package, you are tied to the version of the package that Ember package bundles in. Your only way to updating the "final destination" package is to ask (and then beg) the package maintainer to update the bundled version.

ember-cli-tailwind vs tailwindcss

I got hooked on Tailwind CSS during the workshop the EmberMap guys held at EmberConf in 2018. They published an add-on, ember-cli-tailwind, that made using Tailwind CSS an "ember install" away. It worked great but they recently deprecated it and for good reason: there's no need to maintain an add-on when Tailwind can be used directly and fairly easily at that.

They also released a screencast on how to switch away from ember-cli-tailwind and use the tailwindcss package directly with PostCSS.

In this post, I'll describe how I did the same in the Sac Sac Mate app but slightly differently than they did, as I don't use any pre-processors (they use Sass) in my app.

Installing ember-cli-postcss and tailwindcss

As a first step, we should make our app integrate nicely with PostCSS. We'll still use an integrator add-on for this purpose, ember-cli-postcss:

1$ ember install ember-cli-postcss

We can now install the Tailwind package directly:

1$ yarn add tailwindcss@0.7.4 --dev

I installed 0.7.4 because that's the version that was bundled into ember-cli-tailwind and I don't want to make the upgrade to the latest version in one step – and then fix all the broken styles. If you start with a clean slate, you don't have to define the version string.

We should now remove ember-cli-tailwind:

1$ yarn remove ember-cli-tailwind

PostCSS has to be configured in our Ember app to use Tailwind which happens in the ember-cli-build.js file:

 1// ember-cli-build.js
 2module.exports = function(defaults) {
 3  let app = new EmberApp(defaults, {
 4    postcssOptions: {
 5      compile: {
 6        plugins: [
 7          { module: require('tailwindcss') }
 8        ]
 9      }
10    }
11  });
12}

We can now proceed to use Tailwind just as if we had a "pure Tailwind" install, following the instructions. We can add these lines to the top of our app.css:

1/* app/styles/app.css */
2@tailwind base;
3
4@tailwind components;
5
6@tailwind utilities;

That works, but I already had a few custom styles added to my project, so to restore the original look I needed to copy-paste all of these extra styles to the same file, below the @tailwind directives.

If you want to tweak any style Tailwind provides, you should add a Tailwind configuration file to the project. It's also a good way to see all the utilities Tailwind provides, kind of like a local documentation.

1$ npx tailwind init app/styles/tailwind.js

That creates a tailwind.js file with all the styles. We're not done yet as we have to let our build know where to pick up those rules. Let's open ember-cli-build.js and make that change:

 1// ember-cli-build.js
 2module.exports = function(defaults) {
 3  let app = new EmberApp(defaults, {
 4    postcssOptions: {
 5      compile: {
 6        plugins: [
 7          require('tailwindcss')('./app/styles/tailwind.js'),
 8        ]
 9      }
10    }
11  });
12}

Using postcss-import to clean up

That works but I'm an orderly guy and I wanted to have the custom Tailwind classes and components I added in a separate file and keep the main app.css file clean and tidy.

To be able to import styles from other files, you need postcss-import, so let's start by installing it:

1$ yarn add -D postcss-import

Since postcss-import is a PostCSS plugin, we have to tell PostCSS about it.

 1// ember-cli-build.js
 2module.exports = function(defaults) {
 3  let app = new EmberApp(defaults, {
 4    postcssOptions: {
 5      compile: {
 6        plugins: [
 7          { module: require('postcss-import') },
 8          require('tailwindcss')('./app/styles/tailwind.js'),
 9        ]
10      }
11    }
12  });
13}

Adding postcss-import also changes how we should import the Tailwind styles, to the following:

1/* app/styles/app.css */
2@import "tailwindcss/preflight";
3@import "tailwindcss/components";
4@import "tailwindcss/utilities";
5
6@import "custom-utilities";
 1/* app/styles/custom-utilities.css */
 2.text-beige-light {
 3  color: #f0d9b5;
 4}
 5
 6.bg-beige-light {
 7  background-color: #f0d9b5;
 8}
 9
10.text-beige-darker {
11  color: #b58863;
12}
13
14.bg-beige-darker {
15  background-color: #b58863;
16}
17
18.link {
19  @apply text-blue no-underline;
20}
21
22.link:hover {
23  @apply text-blue-darker;
24}
25/* (...) */

We're done, our styles shine just as before and we decoupled ourselves from ember-cli-tailwind and use Tailwind directly.

What's next?

One thing (and the original reason) this makes possible is to upgrade Tailwind to the latest version. It also allows us to use other, general CSS tools. One of those is Purgecss, a library that removes unused css reducing the bundle size (which is especially useful for a utility-based framework like Tailwind).

Share on Twitter