Building Our Sites with Tailwind CSS & Gulp Plugins

July 21, 2018

I built both Cascadia South and Smart Local Reviews using:

Tailwind | Gulp | Browsersync | PurgeCSS | Uglify | CSSO | PostCSS

Tailwind is the CSS framework for both sites. Browsersync runs while developing the sites, injecting changes and/or reloading the browser whenever the code is modified.

PostCSS is Tailwind’s CSS preprocessor. PurgeCSS removes unused CSS. Uglify minifies Javascript, and CSSO minifies CSS.

You can likely see some obvious design similarities between the two sites. Although Tailwind is very versatile, in the interest of getting sh!t done, I opted to use similar styles and components on both sites.

This has the added effect of making the sites somewhat visually similar for branding purposes, although this was a distant second thought.

Cascadia South has a couple of custom colours added in, but the rest of both sites are using Tailwind’s built-in styles and colours. Eventually, Smart Local Reviews will be redesigned with its own brand colours in mind, but for now, we’re building the minimum viable product, so custom colours and styles are beyond the project’s scope.

Tailwind already has a great and extensive pre-made colour palette, so you’re not stuck with another Bootstrap-looking site even if you stick to the defaults.

I built my personal site (this one!) using Gatsby, but Cascadia South and Smart Local Reviews are put together with boring old PHP for some minor templating (reusable header, footer, etc.).

The eventual goal is to move both sites over to Gatsby or another static site generator. Smart Local Reviews has a full customer dashboard that was built with PHP, and that’s likely to remain for quite a while.

The full gulpfile.js for Cascadia South is below.

const gulp = require('gulp');
const browserSync = require('browser-sync').create();
const purgecss = require('gulp-purgecss');
const csso = require('gulp-csso');
const rename = require("gulp-rename");
var uglify = require('gulp-uglifyes');

class TailwindExtractor {
  static extract(content) {
    return content.match(/[A-z0-9-:\/]+/g);

gulp.task('css', function () {
  var postcss = require('gulp-postcss');
  var tailwindcss = require('tailwindcss');

  return gulp.src('style.css')
      stream: true

gulp.task('browserSync', function() {
    proxy: 'http://localhost/cs2018/live/',

gulp.task('watch',['browserSync','css'], function(){'style.css', ['css'], browserSync.reload);'./live/**/*.php', browserSync.reload);'./live/js/**/*.js', browserSync.reload); 

gulp.task('purgecss', () => {
  return gulp
        content: ['live/**/*.php'],
        extractors: [
            extractor: TailwindExtractor,
            extensions: ['php']
	    whitelist: ['is-active', 'hidden']

gulp.task('styles', function () {
  return gulp.src('live/css/style.css')

gulp.task('minjs', function () {
  return gulp.src('live/js/scripts.js')
       mangle: false, 
       ecma: 6 

gulp.task('compress',['styles','minjs'], function(){})

The highlighted sections above are the pieces that were needed to get PurgeCSS working with Tailwind. It took some Googling and tinkering to get them right. Tailwind uses colons to mark class variations for hover, responsive resolutions, etc. The first piece of code basically tells PurgeCSS to include colon styles in the CSS it generates.

The second piece tells PurgeCSS to use the above code, and to also include specific styles. The .is-active and .hidden classes are not used in the site’s markup, but are used by some of the Javascript. PurgeCSS removes all CSS rules that are not present in the markup, so whitelisting these two classes keeps them in the final CSS file that PurgeCSS generates.

While developing, I run gulp watch in the Terminal. This runs Browsersync, watching the CSS/JS/PHP files and injecting changes live into the browser, and processes Tailwind’s CSS with PostCSS.

When development is done, I run the gulp purgecss task to remove unused CSS, then gulp compress to compress the final CSS and Javascript, and the site is ready to be deployed!

I’m sure there are changes that could be made to the workflow – in fact, just writing out this process has pointed out a few to me – but I’m still relatively new to gulp, so once I got things working, I left them alone. In the future, I’ll return to this setup and refine it.

    You should follow me on Twitter. | Want to work together? Contact me here.