Skip to content

Instantly share code, notes, and snippets.

@somebody32
Last active April 25, 2022 18:24
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save somebody32/48277662e55dd450d542724bc989c62d to your computer and use it in GitHub Desktop.
Save somebody32/48277662e55dd450d542724bc989c62d to your computer and use it in GitHub Desktop.
Tailwind purging + external components library

Prerequisites

  1. The app that uses tailwind + external component library (CL) (but not 3rdparty, your company internal one, for example)
  2. The component library also uses tailwind

The goal

To be able to purge safely unused tailwind classes from the build (https://tailwindcss.com/docs/controlling-file-size)

Solution

The idea here is simple: we're going to purge css on the app side + whitelist classes that component library is using. Initially, I've tried to do that when the whole tailwind build was provided by the CL and purged on that side, however, that way you can't guarantee that you're removing classes which the app is using if there are any.

1. Getting list of used classes from CL

  1. Imagining you have lib/tailwind.css in your CL build with full tailwind
  2. Run purge to leave only used css purgecss -c purgecss.config.js -o lib/
// purgecss.config.js
class TailwindExtractor {
  static extract(content) {
    return content.match(/[A-Za-z0-9-_:\/]+/g) || [];
  }
}

module.exports = {
  content: ["src/components/**/!(stories).js"],
  css: ["lib/tailwind.css"],
  extractors: [{ extractor: TailwindExtractor, extensions: ["js"] }]
}
  1. extract used selectors, ship it as a part of the build as json: node extract-selectors.js
// extract-selectors.js
const listSelectors = require("list-selectors");
const fs = require("fs");

listSelectors(
  ["./lib/tailwind.css"],
  { include: ["classes"] },
  ({ classes }) => {
    fs.writeFileSync(
      "./lib/usedCSSClasses.json",
      JSON.stringify(
        classes.map(c =>
          c
            .substring(1)
            .split("\\")
            .join("")
        )
      )
    );
  }
)

2. Purging code from the app

No magic here, the only diff is to whitelist used classes in CL:

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

function getWhitelist() {
  const whitelistFile = path.resolve(
    "./node_modules/<yourCL>/lib/usedCSSClasses.json"
  );
  return JSON.parse(fs.readFileSync(whitelistFile));
}

const purgeOpts = {
  // ... the rest of your options
  whitelist: getWhitelist, // important that this is a function, so list will be reloaded every time, useful for dev envs
  extractors: [
    {
      extractor: TailwindExtractor,
      extensions: [...]
    }
  ]
}

module.exports = () => new PurgecssPlugin(purgeOpts);

Also would advise it to make it part of your dev config too, so you're not going to have surprises on production/testing envs.

Surprises could be if you're constructing classes dynamically, like bg-${someprop}. That way purge could not see it. So better to use the full string in that case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment