Search code examples
node.jstailwind-csspostcsspurgecss

How to purge unused tailwind css and custom css given a string of HTML


I have a string of HTML. For example, like this

const html = '<html><body><div class="card bg-red-500"></div></body></html>'

I also have a bunch of CSS definitions. Specifically, Tailwind CSS and these custom definitions:

.banner { color: white }

.card { color: red; }

.profile { color: blue }

I want to generate a minimal string of CSS to style this HTML. I.e. I want to purge all the unused CSS classes.

I need to do this from a Node environment.

Near Solution

I can use postcss + tailwindcss to get pretty close..

import postcss from "postcss"
import { default as tailwindcss } from "tailwindcss"

const html = '<html><body><div class="card bg-red-500"></div></body></html>'

const promiseCSS = await postcss([
  tailwindcss({
    content: [{ raw: html }],
  }),
]).process("@tailwind utilities", { from: undefined })


console.log(promiseCSS.css)

// Output:
//
// .bg-red-500 {
//     --tw-bg-opacity: 1;
//     background-color: rgb(239 68 68 / var(--tw-bg-opacity))
// }

but obviously this only processes tailwind utility classes (i.e. @tailwind utilities). So, the resulting CSS string does not include the definition for the .card class.

Attempted solution

I thought I might be able to add my custom CSS to tailwind's utilities, and that would do the trick.

import postcss from "postcss"
import { default as plugin, default as tailwindcss } from "tailwindcss"

const tailwindConfig = {
  plugins: [
    plugin(function ({ addUtilities }) {
      addUtilities({
        ".banner": { color: "white" },
        ".card": { color: "red" },
        ".profile": { color: "blue" },
      })
    }),
  ],
}

const html = '<html><body><div class="card bg-red-500"></div></body></html>'

const promiseCSS = await postcss([
  tailwindcss({
    presets: [tailwindConfig],
    content: [{ raw: html }],
  }),
]).process("@tailwind utilities", { from: undefined })

console.log(promiseCSS.css)

// Output:
//
// .bg-red-500 {
//     --tw-bg-opacity: 1;
//     background-color: rgb(239 68 68 / var(--tw-bg-opacity))
// }

but this produces the same output as before.


Note that this is a toy example. In reality, the "custom" CSS I need to include is this.


Solution

  • It seems your custom plugin isn't actually registering into Tailwind. Consider reworking your imports slightly:

    import { default as tailwindcss } from "tailwindcss"
    import plugin from "tailwindcss/plugin.js"
    

    You could also alternatively have the rules defined in the source CSS:

    const css = `@tailwind utilities;
    
    @layer utilities {
      .banner { color: white }
    
      .card { color: red; }
    
      .profile { color: blue }
    }
    `
    
    const promiseCSS = await postcss([
      tailwindcss({
        content: [{ raw: html }],
      }),
    ]).process(css, { from: undefined })
    

    Example StackBlitz project of this working