Tailwind CSS Purge: Optimize Angular for Production
Remove unused Tailwind CSS utilities from your Angular production build for best performance
- Authors
- Marc Stammerjohann
- Published at
By design, Tailwind CSS generates a large amount of utility classes for your development build. For your Angular application you want the best performance by only including the classes you are actually using in your production build. Tailwind got you covered! PurgeCSS is build-in making it easy to tree-shake unused Tailwind styles for your application.
You are going to learn how to setup Tailwind's purge
option to optimize Tailwind CSS in your Angular and for your Scully Jamstack application.
The purge
options in this post have been tested with Angular 11 and Tailwind CSS 2.0, it also works with Angular 10 and Tailwind CSS 1.9.
Get Started
Get ready with a new or existing Angular + Tailwind CSS application
ng new app-name
# add tailwind
ng add ngx-tailwind
# optional - add jamstack with Scully
ng add @scullyio/init
Now use Tailwind CSS utility classes in your Angular application HTML template, using apply
in your stylesheets or even in your TypeScript files via @HostBinding(...)
.
Purge unused Tailwind CSS utilities in Angular
Tailwind provides a purge option in the tailwind.config.js
file. Purge removes only classes generated by Tailwind or styles added to the @layer
directive. Custom CSS or third-party CSS like Angular Material or Prism.js will not be removed.
Simply provide all your template paths as an array to the purge
option. For an Angular application this would be all HTML and TS files in your src
directory. TS files should be included as they might reference class names using e.g. @HostBinding(...)
.
module.exports = {
purge: ["./src/**/*.html", "./src/**/*.ts"],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Use *.{html,ts}
to match multiple file types in the same directory
module.exports = {
- purge: ["./src/**/*.html", "./src/**/*.ts"],
+ purge: ["./src/**/*.{html,ts}"],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Trigger Tailwind to automatically purge your CSS by setting NODE_ENV=production
during your ng build
step. If you used ngx-tailwind schematics to setup Tailwind it automatically added a production script to your package.json. Additionally, the latest release of ngx-tailwind@1.1.0 adds the above purge options automatically to your tailwind.config.js
.
{
"scripts": {
"build:prod": "NODE_ENV=production ng build --prod"
}
}
Now run npm run build:prod
to only include used Tailwind CSS utilities in your Angular production build. This even works great in your Scully application
Advanced Purge options
purge
also accepts an options object for further optimizations. Available purge
options are enabled, content
for your template paths, preserveHtmlElements, layers, mode and last options to pass it directly to PurgeCSS. The defaults for these options are:
module.exports = {
purge: {
// enabled: true, // enabled by `NODE_ENV=production` or enable manually
mode: 'layers', // or 'all' ☠️ be careful
preserveHtmlElements: true, // or false ⚠️ not generally recommended
layers: ['base', 'components', 'utilities'], // remove layers to ignore from purging
content: [], // add your template paths
options: { /* PurgeCSS options */}
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Too use the object syntax for the purge
option add the template paths to the content
option
module.exports = {
purge: {
content: ["./src/**/*.{html,ts}"]
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Go ahead and provide additional options to the purge
object to further optimize your production build based on your application. For specific configurations pass it directly to PurgeCSS using the options
key. You can provide safelist
, blocklist
, extractors
and more.
module.exports = {
purge: {
content: ["./src/**/*.html", "./src/**/*.ts"],
// These options are passed through directly to PurgeCSS
options: {
safelist: ['bg-red-500', /^mat-/],
blocklist: ['bg-orange-500', /^cdk-/],
extractors: [],
...
}
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Let's improve purging for a Scully application by writing an extractor
for your Markdown content files to detect which HTML tags and CSS classes are actually used.
Purge Scully Markdown content
Scully organizes the content of your static-site in Markdown files. Add the path to your Markdown files e.g. './blog/**/*.md'
to the content
array. Create an extractor targeting only files with the Markdown extension md
.
module.exports = {
purge: {
content: ['./src/**/*.{html,ts}', './blog/**/*.md'],
options: {
extractors: [
{
extensions: ['md'],
extractor: (content) => {
return [];
},
},
],
},
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Before matching HTML elements and CSS classes you need to parse the Markdown content to HTML. Scully uses marked to parse your Markdown content files. Let's require it in the tailwind.config.js
and parse the content in the extractor.
const marked = require('marked');
module.exports = {
purge: {
content: ['./src/**/*.{html,ts}', './blog/**/*.md'],
options: {
extractors: [
{
extensions: ['md'],
extractor: (content) => {
content = marked(content);
return [];
},
},
],
},
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Let's use the Regex used by blog.tailwindcss.com to find all used HTML elements and classes. Also set the mode: 'all'
☠️ and preserveHtmlElements: false
⚠️ to remove unused tags like h4
and more.
const marked = require('marked');
module.exports = {
purge: {
model: 'all',
preserveHtmlElements: false,
content: ['./src/**/*.{html,ts}', './blog/**/*.md'],
options: {
extractors: [
{
extensions: ['md'],
extractor: (content) => {
content = marked(content);
// Capture as liberally as possible, including things like `h-(screen-1.5)`
const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []
// Capture classes within other delimiters like .block(class="w-1/2") in Pug
const innerMatches =
content.match(/[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g) || []
return broadMatches.concat(innerMatches);
},
},
],
},
},
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
Perfect, now your Angular or Scully applications are optimized for production and you are ready to deploy it to Firebase Hosting or other services.
Sponsor us
Did you find this post useful? We at notiz.dev write about our experiences developing Apps, Websites and APIs and develop Open Source tools. Your support would mean a lot to us 🙏. Receive a reward by sponsoring us on Patreon or start with a one-time donation on GitHub Sponsors.