Integrasi Tailwind CSS dengan Hugo melalui PostCSS adalah kombinasi yang powerful untuk membangun website modern. Tutorial ini akan membimbing Anda dari setup awal hingga optimasi production-ready.
Apa itu Tailwind CSS dan PostCSS?
Tailwind CSS
Tailwind adalah utility-first CSS framework yang memungkinkan styling langsung di HTML tanpa menulis CSS custom. Keunggulan:
- Utility classes: Ratusan class siap pakai (flex, pt-4, text-center, etc)
- Highly customizable: Konfigurasi melalui JavaScript
- JIT mode: Generate hanya class yang digunakan
- Responsive design: Breakpoint built-in (sm, md, lg, xl)
- Dark mode: Support otomatis
PostCSS
PostCSS adalah tool untuk transformasi CSS dengan JavaScript plugins:
- Autoprefixer: Menambahkan vendor prefixes otomatis
- CSS nesting: Support nested selectors
- Custom properties: CSS variables dengan fallback
- Future CSS: Polyfill fitur CSS modern
- Minification: Compress CSS untuk production

Prerequisites
Yang Harus Diinstall
- Hugo Extended: Pastikan menggunakan versi extended untuk support PostCSS
“`bash
# Cek versi Hugo
hugo version
# Harus ada kata “extended” di output
# Contoh: hugo v0.123.0+extended linux/amd64
“`
- Node.js dan NPM: Untuk mengelola packages
bash
node --version # v18 atau lebih tinggi
npm --version
- Text Editor: VS Code dengan ekstensi:
– Tailwind CSS IntelliSense
– PostCSS Language Support
– Hugo Language and Syntax Support
Step-by-Step Setup
Step 1: Inisialisasi Project Node.js
Di root project Hugo Anda:
# Inisialisasi package.json
npm init -y
Install Tailwind CSS dan PostCSS
npm install -D tailwindcss postcss autoprefixer
Generate config file Tailwind
npx tailwindcss init -p
Output yang akan dihasilkan:
– package.json – File konfigurasi NPM
– tailwind.config.js – Konfigurasi Tailwind
– postcss.config.js – Konfigurasi PostCSS
Step 2: Konfigurasi Tailwind CSS
Edit file tailwind.config.js:
/** @type {import('tailwindcss').Config} */module.exports = { content: [ // Path ke semua template Hugo './layouts/**/*.html', './content/**/*.md', './content/**/*.html', './assets/**/*.js',// Jika menggunakan themes './themes/**/layouts/**/*.html', // HUGO_ENVIRONMENT adalah production ...(process.env.HUGO_ENVIRONMENT === 'production' ? [] : ['./layouts/_default/*.html']),],
theme: {
extend: {
// Custom colors
colors: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
900: '#1e3a8a',
},
secondary: '#64748b',
},// Custom font families fontFamily: { sans: ['Inter', 'system-ui', 'sans-serif'], serif: ['Merriweather', 'serif'], }, // Custom spacing spacing: { '128': '32rem', '144': '36rem', }, // Custom breakpoints screens: { 'xs': '475px', '3xl': '1600px', }, },},
plugins: [
// Tambahkan plugin jika diperlukan
// require('@tailwindcss/typography'),
// require('@tailwindcss/forms'),
],// Optimasi untuk production
purge: {
enabled: process.env.HUGO_ENVIRONMENT === 'production',
content: [
'./layouts/*
/.html',
'./content/*
/.md',
],
},
}Penjelasan konfigurasi:
–content: Path file yang akan di-scan Tailwind untuk menemukan class yang digunakan
–theme.extend: Menambahkan custom values tanpa override defaults
–purge: Menghapus unused CSS di production (sangat penting untuk ukuran file kecil)Step 3: Setup PostCSS
Edit file
postcss.config.js:module.exports = { plugins: { tailwindcss: {}, autoprefixer: { overrideBrowserslist: [ '> 1%', 'last 2 versions', 'not dead', 'not ie 11', ], }, }, }Konfigurasi Autoprefixer:
–> 1%: Support browser dengan usage > 1%
–last 2 versions: 2 versi terakhir dari setiap browser
–not dead: Exclude browser yang tidak lagi maintainedStep 4: Buat File CSS Entry Point
Buat folder
assets/css/dan filemain.css:/* assets/css/main.css *// Import Tailwind directives / @tailwind base; @tailwind components; @tailwind utilities;
/ Base layer - style dasar / @layer base { body { @apply antialiased text-gray-900 bg-white leading-relaxed; }
h1, h2, h3, h4, h5, h6 { @apply font-bold tracking-tight text-gray-900; }
h1 { @apply text-4xl md:text-5xl lg:text-6xl; }
h2 { @apply text-3xl md:text-4xl; }
h3 { @apply text-2xl md:text-3xl; }
p { @apply mb-4; }
a { @apply text-primary-600 hover:text-primary-800 transition-colors; }
img { @apply max-w-full h-auto rounded-lg; } }
/ Components layer - reusable components / @layer components { .btn { @apply px-4 py-2 rounded-lg font-medium transition-all duration-200; }
.btn-primary { @apply btn bg-primary-600 text-white hover:bg-primary-700; }
.btn-secondary { @apply btn bg-gray-200 text-gray-800 hover:bg-gray-300; }
.card { @apply bg-white rounded-xl shadow-md p-6 hover:shadow-lg transition-shadow; }
.prose-custom { @apply prose prose-lg max-w-none prose-headings:font-bold prose-a:text-primary-600; } }
/ Utilities layer - custom utilities / @layer utilities { .text-shadow { text-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.bg-gradient-primary { @apply bg-gradient-to-r from-primary-500 to-primary-700; } }
Step 5: Integrasi dengan Hugo Templates
Edit atau buat
layouts/partials/head.html:<head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} | {{ .Site.Title }}{{ end }}</title><!-- Hugo Pipes: Process CSS dengan PostCSS --> {{ $css := resources.Get "css/main.css" }} {{ if $css }} {{ $css = $css | resources.PostCSS }}
{{ if hugo.IsProduction }} {{ $css = $css | resources.Minify | resources.Fingerprint "sha512" }} <link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $css.Data.Integrity }}" crossorigin="anonymous"> {{ else }} <link rel="stylesheet" href="{{ $css.RelPermalink }}"> {{ end }}{{ end }}
<!-- Meta tags SEO -->
<meta name="description" content="{{ .Description | default .Site.Params.description }}">
<meta name="author" content="{{ .Site.Params.author }}"><!-- Open Graph -->
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{ .Description }}">
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}">
<meta property="og:url" content="{{ .Permalink }}">
{{ with .Params.image }}
<meta property="og:image" content="{{ . | absURL }}">
{{ end }}
</head>Penjelasan Hugo Pipes:
–resources.Get: Mengambil file dari folderassets/
–resources.PostCSS: Memproses CSS dengan PostCSS (menjalankan Tailwind + Autoprefixer)
–resources.Minify: Compress CSS untuk production
–resources.Fingerprint: Menambahkan hash untuk cache bustingStep 6: Update Hugo Configuration
Tambahkan di
hugo.toml:[build] writeStats = true # Penting untuk Tailwind JIT mode[imaging] quality = 80 resampleFilter = "lanczos"
[minify] disableCSS = false disableHTML = false disableJS = false
Development Workflow
Mode Development
# Terminal 1: Hugo server hugo server -D --bind 0.0.0.0Terminal 2: Watch Tailwind (opsional jika Hugo tidak auto-reload CSS)
npx tailwindcss -i ./assets/css/main.css -o ./static/css/output.css --watch
Tapi dengan Hugo Pipes, Anda cukup:
hugo server -DHugo akan otomatis:
1. Watch file changes
2. Re-process CSS dengan PostCSS
3. Live reload browserMode Production
# Set environment variable export HUGO_ENVIRONMENT=productionBuild dengan minification
hugo --gc --minify
Cek ukuran file CSS
du -h public/css/*.css
Advanced Configuration
Dark Mode Support
Update
tailwind.config.js:module.exports = { darkMode: 'class', // atau 'media' // ... rest of config }Update CSS:
@layer base { body { @apply antialiased text-gray-900 bg-white; @apply dark:text-gray-100 dark:bg-gray-900; } }Toggle dark mode dengan JavaScript:
// assets/js/darkmode.js const themeToggle = document.getElementById('theme-toggle'); const html = document.documentElement;themeToggle?.addEventListener('click', () => { html.classList.toggle('dark'); localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light'); });
// Check saved preference if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { html.classList.add('dark'); }
Custom Fonts dengan Tailwind
Download atau CDN: Saya sarankan menggunakan Google Fonts atau self-host
Update tailwind.config.js:
module.exports = { theme: { extend: { fontFamily: { sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'], display: ['Cal Sans', 'Inter', 'sans-serif'], }, }, }, }
- Load fonts di head.html:
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">Container Queries (Modern CSS)
Install plugin:
npm install -D @tailwindcss/container-queriesUpdate config:
module.exports = { plugins: [ require('@tailwindcss/container-queries'), ], }Penggunaan:
<div class="@container"> <div class="@lg:grid-cols-3"> <!-- Responsive berdasarkan container, bukan viewport --> </div> </div>Optimasi Production
Bundle Size Analysis
Install plugin:
npm install -D @tailwindcss/typographyAnalisis bundle:
# Build dan cek ukuran hugo --minify ls -lh public/css/Gunakan PurgeCSS lebih agresif jika perlu
Critical CSS
Extract critical CSS untuk above-the-fold content:
{{ $critical := resources.Get "css/critical.css" | resources.PostCSS | resources.Minify }} <style>{{ $critical.Content | safeCSS }}</style><!-- Load non-critical CSS async --> <link rel="preload" href="{{ $css.RelPermalink }}" as="style" onload="this.onload=null;this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="{{ $css.RelPermalink }}"></noscript>
Preload Font Files
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>Troubleshooting
CSS Tidak Ter-apply
Ceklist:
1. ✅ Hugo Extended terinstall
2. ✅resources.PostCSSdi template
3. ✅contentpaths ditailwind.config.jsbenar
4. ✅ File CSS diassets/css/bukanstatic/
5. ✅ Restart Hugo server setelah config changesBuild Failed: “PostCSS not found”
Solusi:
# Pastikan node_modules terinstall npm installCek Hugo version (harus extended)
hugo version | grep extended
Jika tidak extended, install ulang:
macOS
brew uninstall hugo && brew install hugo
Windows
choco uninstall hugo && choco install hugo-extended
Tailwind Classes Not Generated
Debug:
Cek
contentpaths:javascript
content: [
'./layouts/**/*.html', // Pastikan path benar
'./content/**/*.md', // Periksa semua content
'./themes/**/layouts/**/*.html', // Jika pakai theme
],Verifikasi JIT mode aktif:
javascript
module.exports = {
mode: 'jit', // atau pastikan Tailwind v3+
// ...
}Cek classes yang ditulis:
“`html
“`Slow Build Time
Optimasi:
# Gunakan --disableFastRender untuk development cepat hugo server --disableFastRenderAtau --gc untuk garbage collection
hugo server --gc
Update
tailwind.config.js:module.exports = { content: [ // Hanya include file yang perlu di-scan './layouts/**/*.html', './content/**/*.md', // Hindari: './node_modules/**/*' (bikin lambat) ], }Testing dan Validasi
1. Visual Regression Testing
Gunakan tools seperti:
- Percy
- Chromatic
- BackstopJS
2. Accessibility Testing
# Install axe-core npm install -D @axe-core/cliTest
npx axe http://localhost:1313
3. Performance Testing
- Lighthouse: Chrome DevTools > Lighthouse
- WebPageTest: webpagetest.org
- PageSpeed Insights: developers.google.com/speed/pagespeed/insights
Best Practices
1. Utility-First Approach
<!-- ✅ Benar: Utility classes --> <div class="flex items-center justify-between p-4 bg-white shadow rounded-lg"> <h1 class="text-2xl font-bold text-gray-900">Judul</h1> <button class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"> Action </button> </div><!-- ❌ Hindari: Custom CSS yang panjang --> <div class="custom-card"> <h1 class="custom-title">Judul</h1> <button class="custom-button">Action</button> </div>
2. Extract Components untuk Reusability
Gunakan
@applyuntuk komponen yang sering dipakai:@layer components { .btn { @apply px-4 py-2 rounded-lg font-medium transition-all duration-200; }.btn-primary { @apply btn bg-primary-600 text-white hover:bg-primary-700 focus:ring-2 focus:ring-primary-500; } }
3. Responsive Design Mobile-First
<!-- Mobile-first: default untuk mobile, override untuk desktop --> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <!-- 1 kolom di mobile, 2 di tablet, 3 di desktop --> </div><!-- Padding responsive --> <div class="p-4 md:p-6 lg:p-8"> <!-- Padding bertambah di device lebih besar --> </div>
4. Semantic HTML dengan Tailwind
<!-- ✅ Semantic + Tailwind --> <article class="prose prose-lg max-w-none"> <header class="mb-8"> <h1 class="text-4xl font-bold text-gray-900">{{ .Title }}</h1> <time class="text-gray-500" datetime="{{ .Date.Format "2006-01-02" }}"> {{ .Date.Format "2 January 2006" }} </time> </header><div class="prose-content"> {{ .Content }} </div> </article>
Kesimpulan
Integrasi Tailwind CSS dengan Hugo melalui PostCSS memberikan workflow development yang modern dan efisien:
✅
Kecepatan Development: Utility classes mempercepat styling
✅
Ukuran File Kecil: JIT mode hanya generate class yang dipakai
✅
Konsistensi: Design system built-in
✅
Responsif: Mobile-first approach
✅
Customizable: Extend sesuai kebutuhan brandDengan setup yang benar, Anda akan mendapatkan CSS bundle yang ter-optimasi otomatis untuk production tanpa effort manual.
Ditulis oleh
Hendra Wijaya