Tutorial Konfigurasi Tailwind CSS di Hugo dengan PostCSS
Tutorial Konfigurasi Tailwind CSS di Hugo dengan PostCSS
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
# Cek versi Hugo hugo version # Harus ada kata "extended" di output # Contoh: hugo v0.123.0+extended linux/amd64Node.js dan NPM: Untuk mengelola packages
node --version # v18 atau lebih tinggi npm --versionText 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 NPMtailwind.config.js- Konfigurasi Tailwindpostcss.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 digunakantheme.extend: Menambahkan custom values tanpa override defaultspurge: 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 browsernot dead: Exclude browser yang tidak lagi maintained
Step 4: Buat File CSS Entry Point
Buat folder assets/css/ dan file main.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 productionresources.Fingerprint: Menambahkan hash untuk cache busting
Step 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.0
# Terminal 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 -D
Hugo akan otomatis:
- Watch file changes
- Re-process CSS dengan PostCSS
- Live reload browser
Mode Production
# Set environment variable
export HUGO_ENVIRONMENT=production
# Build 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-queries
Update 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/typography
Analisis 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:
- ✅ Hugo Extended terinstall
- ✅
resources.PostCSSdi template - ✅
contentpaths ditailwind.config.jsbenar - ✅ File CSS di
assets/css/bukanstatic/ - ✅ Restart Hugo server setelah config changes
Build Failed: “PostCSS not found”
Solusi:
# Pastikan node_modules terinstall
npm install
# Cek 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:content: [ './layouts/**/*.html', // Pastikan path benar './content/**/*.md', // Periksa semua content './themes/**/layouts/**/*.html', // Jika pakai theme ],Verifikasi JIT mode aktif:
module.exports = { mode: 'jit', // atau pastikan Tailwind v3+ // ... }Cek classes yang ditulis:
<!-- Benar --> <div class="flex items-center justify-center"> <!-- Salah (typo) --> <div class="flexx item-center">
Slow Build Time
Optimasi:
# Gunakan --disableFastRender untuk development cepat
hugo server --disableFastRender
# Atau --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/cli
# Test
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 @apply untuk 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 brand
Dengan setup yang benar, Anda akan mendapatkan CSS bundle yang ter-optimasi otomatis untuk production tanpa effort manual.
Artikel Terkait
Link Postingan : https://www.tirinfo.com/tutorial-tailwind-hugo-postcss/