- The app that uses tailwind + external component library (CL) (but not 3rdparty, your company internal one, for example)
- The component library also uses tailwind
To be able to purge safely unused tailwind classes from the build (https://tailwindcss.com/docs/controlling-file-size)
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.
- Imagining you have
lib/tailwind.css
in your CL build with full tailwind - 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"] }]
}
- 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("")
)
)
);
}
)
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.