Setting up Tailwind CSS with Vue.js

Tailwind CSS is one of the rising stars in the CSS framework world. It’s especially popular in the Laravel and Vue.js community. So in my next two articles, we take a closer look at this utility-first CSS framework.

In this article, we learn how to set up Tailwind CSS to work with a Vue CLI powered application. Because Tailwind CSS is a utility-first CSS framework which provides a lot of utility classes out of the box, its file size without any optimizations is pretty massive (350.4kb / 58.8kb gzipped). But luckily, we can use PurgeCSS to improve the final bundle size of our application tremendously.

This is the first part of a short AUSFLUG into the world of utility-first CSS frameworks. In the second part, we find out how to build highly maintainable applications with Tailwind CSS and Vue.js by utilizing the power of functional UI components. If you want to be informed about the second part, you can follow me on Twitter or subscribe to my newsletter.

If you want to take a look at the final code, you can check out the full code on GitHub.

Using Tailwind CSS with Vue CLI

Before we can get started building Tailwind CSS powered Vue.js applications, we have to set it up.

npm install tailwindcss
// postcss.config.js
const autoprefixer = require('autoprefixer');
const tailwindcss = require('tailwindcss');

module.exports = {
  plugins: [
    tailwindcss,
    autoprefixer,
  ],
};

After installing tailwindcss as a dependency of our project and adding it to the list of PostCSS plugins inside of our postcss.config.js file, we are ready to import Tailwind CSS into our project.

// src/assets/styles/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
 // src/main.js
 import Vue from 'vue';
 import App from './App.vue';

+import './assets/styles/index.css';

 Vue.config.productionTip = false;

 new Vue({
   render: h => h(App),
 }).$mount(`#app`);

First, we create a new index.css file in src/assets/styles and load all Tailwind related styles in it. Next, we import this newly created file inside of our main main.js entry point of our app.

Customizing the Tailwind configuration

If we want to change certain aspects of our Tailwind CSS setup, we can create a configuration file. This makes it possible to change things like the font family, colors, margins, and even the media query breakpoints, for example.

npx tailwind init

This creates a new file, tailwind.config.js in the root directory of our application. We can use this configuration file to adapt Tailwind CSS to our needs.

// tailwind.config.js
module.exports = {
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
};

Reducing file size with PurgeCSS

Now we have everything set up to start building Tailwind powered applications. But if we take a closer look at the final bundle size of our app, we notice that Tailwind adds a considerable large chunk of CSS. Fortunately, we can work around this by adding PurgeCSS to our Vue.js project.

npm install @fullhuman/postcss-purgecss --save-dev

After installing the postcss-purgecss plugin, we must add it to our postcss.config.js.

 // postcss.config.js
 const autoprefixer = require('autoprefixer');
 const tailwindcss = require('tailwindcss');
+const postcssPurgecss = require(`@fullhuman/postcss-purgecss`);

+const purgecss = postcssPurgecss({
+  // Specify the paths to all of the template files in your project.
+  content: [
+    './public/**/*.html',
+    './src/**/*.vue',
+  ],
+  // Include any special characters you're using in this regular expression.
+  // See: https://tailwindcss.com/docs/controlling-file-size/#understanding-the-regex
+  defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [],
+  // Whitelist auto generated classes for transitions and router links.
+  // From: https://github.com/ky-is/vue-cli-plugin-tailwind
+  whitelistPatterns: [/-(leave|enter|appear)(|-(to|from|active))$/, /^(?!(|.*?:)cursor-move).+-move$/, /^router-link(|-exact)-active$/],
+});

 module.exports = {
   plugins: [
     tailwindcss,
     autoprefixer,
+    ...process.env.NODE_ENV === 'production'
+      ? [purgecss]
+      : [],
   ],
 };

First, we add the ./public/**/*.html directory to the list of directories to watch for HTML files, so PurgeCSS does not remove the default <html> and <body> styles added by Tailwind CSS to reset the browser default styles. Next, we change the defaultExtractor to work with Tailwind.

As you can see above, we only add the purgecss plugin in production mode. This makes development faster but also comes with the downside that we might not be aware of the fact that PurgeCSS removes certain CSS styles because we did not write our CSS classes correctly inside of our components.


Do you want to learn more about advanced Vue.js techniques?

Register for the Newsletter of my upcoming book: Advanced Vue.js Application Architecture.


Writing purgeable Vue components

As it’s stated in the official Tailwind CSS documentation, we have to follow some rules to avoid PurgeCSS removing CSS styles, which it is not supposed to remove.

<template>
  <Component
    :is="`h${level}`"
    :class="`font-light leading-tight text-${size}xl`"
  >
    <slot/>
  </Component>
</template>

In the example headline component above, we use template-strings to programmatically set the tag rendered for the component and the text size class. This is problematic when using PurgeCSS. Because that way, it does not know that the styles for the h1-6 tags and the text-1xl, text-2xl, … classes are necessary and must not be purged.

 <template>
   <Component
-    :is="`h${level}`"
+    :is="'h1', 'h2', 'h3', 'h4', 'h5', 'h6'][level - 1]"
-    :class="`font-light leading-tight text-${size}xl`"
+    class="font-light leading-tight"
+    :class="[
+      ...(size <= 1 ? 'text-1xl'] : []),
+      ...(size === 2 ? 'text-2xl'] : []),
+      ...(size === 3 ? 'text-3xl'] : []),
+      ...(size === 4 ? 'text-4xl'] : []),
+    ]"
   >
     <slot/>
   </Component>
 </template>

Unfortunately, this approach is a lot more verbose than the initial solution, but this is one of the tradeoffs we have to take when using PurgeCSS.

Keep in mind that every CSS class or HTML tag has to appear as plain text string somewhere in your Vue.js components if you don’t want PurgeCSS to remove the corresponding styles.

Wrapping it up

Although setting up Tailwind CSS to work with Vue.js is rather straightforward, things become a little more tricky after also adding PurgeCSS into the mix.

But this was only the beginning: now you are ready to read the next article about how to build reusable functional components with Tailwind CSS and Vue.js.

References


Do you want to learn how to build advanced Vue.js applications?

Register for the Newsletter of my upcoming book: Advanced Vue.js Application Architecture.



Do you enjoy reading my blog?

You can buy me a ☕️ on Ko-fi!