Watching TailwindCSS changes with Snowpack

Watching TailwindCSS changes with Snowpack

Let me start with a quick introduction, in case you are not familiar with TailwindCSS and Snowpack.

TailwindCSS, as they put it on their website, is a "utility-first CSS framework for rapidly building custom designs". Snowpack, also as they describe it, is "a modern frontend build tool for faster web development", which "replaces heavier, more complex bundlers like Webpack or Parcel in your development workflow."

I was recently working on a basic app using these tools. When I say basic I mean just plain HTML, CSS and JavaScript. No React, Vue, Svelte or others. My main goal was to explore how TailwindCSS and Snowpack played along, without the need of any of the official or community plugins generally tied to the aforementioned frameworks.

Basic markup works as expected

Adding TailwindCSS classes in your HTML works as expected. Snowpack delivers on its promise of quickly updating and refreshing your browser.

<!-- sample HTML, no problem here (index.html) -->
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
  Button
</button>

Advanced Feature Hiccup on Save

At some point, writing markup as shown above can get out of hand and hard to read. Imagine the list of classes growing past 80 characters or to a second line, and having to write the same thing multiple times. You would definitely want a different approach.

TailwindCSS offers advanced features like the @apply directive, which allows you to extract CSS components. The code below shows an alternative to the markup I showed above (an example from the documentation).

<button class="btn-blue">
  Button
</button>
/* In my test src/styles.css gets compiled to public/styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn-blue {
    @apply bg-blue-500 text-white font-bold py-2 px-4 rounded;
  }
  .btn-blue:hover {
    @apply bg-blue-700;
  }
}

This is definitely an improvement, but Snowpack did not process the changes on file save. As you can see, the difference here is that rather than editing the HTML file, I edited the CSS file, and this file needs to be compiled and updated in the public directory. You can compile via the "tailwind" or the "postcss" command.

A Script to the Rescue

After trial an error and going through Snowpack, TailwindCSS and PostCSS documentation a few times, I came to realize that Snowpack offers a feature that allows you to run a script via @snowpack/plugin-run-script. Therefore, there is no need to add the compilation script in package.json. Technically you can, but you won't be able to take advantage of the "watch" process available through PostCSS-CLI in combination with the Snowpack "plugin-run-script" feature.

So, to fix this you would need to first install the plugin:

npm i @snowpack/plugin-run-script

Next, update the Snowpack configuration file, snowpack.config.json, with the PostCSS commands:

 "plugins": [
    [
      "@snowpack/plugin-run-script",
      {
        "cmd": "postcss src/styles.css -o public/styles.css",
        "watch": "postcss src/styles.css -o public/styles.css -w"
      }
    ]
  ]

Once you make those changes, make sure to run npm start (which runs snowpack dev), and next time you make changes in the CSS file and save them, Snowpack should be watching and running the compilation for you.

Just in case, this is what my package.json file looks like:

  "scripts": {
    "start": "snowpack dev",
    "build": "snowpack build",
    "test": "echo \"This template does not include a test runner by default.\" && exit 1",
    "format": "prettier --write \"src/**/*.js\"",
    "lint": "prettier --check \"src/**/*.js\""
  },
  "dependencies": {
    "@snowpack/plugin-run-script": "^2.1.5",
    "tailwindcss": "^1.8.10"
  },
  "devDependencies": {
    "postcss": "^8.1.1",
    "postcss-cli": "^8.0.0",
    "prettier": "^2.0.5",
    "snowpack": "^2.12.0"
  }
}

References:

TailwindCSS Snowpack PostCSS PostCSS-CLI

Photo by Kameron Kincade on Unsplash