Lewati ke konten
Kembali ke Blog

Tutorial Konfigurasi Tailwind CSS di Hugo dengan PostCSS

· · 11 menit baca

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

Tailwind CSS Architecture

Prerequisites

Yang Harus Diinstall

  1. 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
“`

  1. Node.js dan NPM: Untuk mengelola packages

bash
node --version # v18 atau lebih tinggi
npm --version

  1. 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 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 &quot;sha512&quot; }}
  &lt;link rel=&quot;stylesheet&quot; href=&quot;{{ $css.RelPermalink }}&quot; integrity=&quot;{{ $css.Data.Integrity }}&quot; crossorigin=&quot;anonymous&quot;&gt;
{{ else }}
  &lt;link rel=&quot;stylesheet&quot; href=&quot;{{ $css.RelPermalink }}&quot;&gt;
{{ 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 folder assets/
resources.PostCSS: Memproses CSS dengan PostCSS (menjalankan Tailwind + Autoprefixer)
resources.Minify: Compress CSS untuk production
resources.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:
1. Watch file changes
2. Re-process CSS dengan PostCSS
3. 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

  1. Download atau CDN: Saya sarankan menggunakan Google Fonts atau self-host

  2. Update tailwind.config.js:

module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'],
        display: ['Cal Sans', 'Inter', 'sans-serif'],
      },
    },
  },
}
  1. 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:
1. ✅ Hugo Extended terinstall
2. ✅ resources.PostCSS di template
3. ✅ content paths di tailwind.config.js benar
4. ✅ File CSS di assets/css/ bukan static/
5. ✅ 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:

  1. Cek content paths:
    javascript
    content: [
    './layouts/**/*.html', // Pastikan path benar
    './content/**/*.md', // Periksa semua content
    './themes/**/layouts/**/*.html', // Jika pakai theme
    ],

  2. Verifikasi JIT mode aktif:
    javascript
    module.exports = {
    mode: 'jit', // atau pastikan Tailwind v3+
    // ...
    }

  3. Cek classes yang ditulis:
    “`html

“`

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.

Ditulis oleh

Hendra Wijaya

Tinggalkan Komentar

Email tidak akan ditampilkan.