Loading...
Loading...
Use when optimizing Tailwind CSS for production, reducing bundle size, and improving performance. Covers PurgeCSS, JIT mode, and build optimization.
npx skill4agent add thebushidocollective/han tailwind-performance// tailwind.config.js (JIT is default, no config needed)
module.exports = {
content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
// JIT mode is automatic
}module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
'./app/**/*.{js,jsx,ts,tsx}',
// Include any files that contain Tailwind classes
'./public/index.html',
],
}// Good: Specific paths
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
],
}
// Bad: Too broad
module.exports = {
content: [
'./**/*.{js,jsx,ts,tsx}', // Scans node_modules!
],
}module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
safelist: [
'bg-red-500',
'bg-green-500',
'bg-blue-500',
// Or use patterns
{
pattern: /bg-(red|green|blue)-(400|500|600)/,
variants: ['hover', 'focus'],
},
],
}// Bad: These classes won't be detected
<div className={`text-${size}`}>
<div className={`bg-${color}-500`}>
// Good: Use complete class names
<div className={size === 'large' ? 'text-lg' : 'text-sm'}>
<div className={color === 'red' ? 'bg-red-500' : 'bg-blue-500'}>
// Or use safelist for dynamic values/* Bad: Custom CSS that duplicates utilities */
.my-button {
background-color: #3b82f6;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
}
/* Good: Use utilities or @apply */
@layer components {
.my-button {
@apply bg-blue-500 text-white px-4 py-2 rounded-md;
}
}
/* Better: Component abstraction (no custom CSS) */// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
},
}:root {
--color-primary: 59 130 246; /* RGB */
}
[data-theme='dark'] {
--color-primary: 96 165 250;
}// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
},
}// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
css: {
postcss: './postcss.config.js',
},
build: {
cssMinify: 'esbuild', // Fast CSS minification
rollupOptions: {
output: {
manualChunks: {
// Separate vendor chunks
vendor: ['react', 'react-dom'],
},
},
},
},
})// next.config.js
module.exports = {
experimental: {
optimizeCss: true, // Enable CSS optimization
},
// Next.js automatically optimizes Tailwind
}// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin(),
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
}// Using dynamic imports
const HeavyComponent = lazy(() => import('./HeavyComponent'))
// Tailwind classes in HeavyComponent will be in a separate chunk<!DOCTYPE html>
<html>
<head>
<style>
/* Inline critical CSS */
.hero { /* ... */ }
.nav { /* ... */ }
</style>
<!-- Load full CSS async -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>// Load additional styles when needed
if (shouldLoadDarkMode) {
import('./dark-mode.css')
}// tailwind.config.js
module.exports = {
theme: {
extend: {
fontFamily: {
sans: [
'Inter var',
'system-ui',
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'sans-serif',
],
},
},
},
}/* Use font-display for better loading */
@font-face {
font-family: 'Inter var';
font-style: normal;
font-weight: 100 900;
font-display: swap; /* Prevent invisible text */
src: url('/fonts/inter-var.woff2') format('woff2');
}# Analyze CSS bundle size
npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify
# Check file size
ls -lh dist/output.css
# Detailed analysis with webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer✅ Content paths are specific and optimized
✅ JIT mode is enabled (default in Tailwind 3+)
✅ CSS is minified in production
✅ Unused styles are purged
✅ Dynamic classes use safelist
✅ Critical CSS is inlined
✅ Fonts use font-display: swap
✅ CSS is code-split by route/chunk
✅ Gzip/Brotli compression enabled
✅ CSS file has content hash for caching// package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:css": "tailwindcss -i ./src/input.css -o ./dist/output.css --minify",
"analyze": "npm run build && webpack-bundle-analyzer dist/stats.json"
}
}// tailwind.config.js
module.exports = {
content: {
files: [
'./src/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
],
// Only in dev: watch for changes
relative: process.env.NODE_ENV === 'development',
},
theme: {
extend: {
// Only extend what you need
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
},
plugins: [
// Only include plugins you use
require('@tailwindcss/forms'),
],
// Disable unused variants
corePlugins: {
// Disable unused features
preflight: true,
// Only enable what you need
},
}<!-- Bad: CDN (3.5MB+, not optimized) -->
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@3/dist/tailwind.min.css" rel="stylesheet">
<!-- Good: Bundled & optimized (typically 5-20KB gzipped) -->
<link href="/dist/styles.css" rel="stylesheet"><!-- Never do this in production -->
<script src="https://cdn.tailwindcss.com"></script>// Bad: Scans everything including node_modules
content: ['./**/*.html']
// Good: Specific to your source files
content: ['./src/**/*.{html,js,jsx,ts,tsx}']// Bad: Class won't be included in build
const colors = ['red', 'blue', 'green']
<div className={`bg-${colors[index]}-500`} />
// Good: Use safelist or conditional classes// Bad: Imports all of Tailwind
import 'tailwindcss/tailwind.css'
// Good: Import only what you built
import './styles.css'// Bad: Never do this
module.exports = {
content: [], // Empty = no purging!
}/* Bad: Defeating the purpose of utilities */
.btn { @apply px-4 py-2 bg-blue-500 text-white rounded; }
.card { @apply p-6 bg-white shadow-lg rounded-lg; }
.header { @apply flex items-center justify-between p-4; }
/* ...hundreds of components */
/* This negates Tailwind's optimization benefits */# Pay attention to warnings like:
# "The content option in your Tailwind CSS configuration is missing or empty"
# "No utility classes were detected in your source files"