Page Bundles adalah fitur powerful di Hugo untuk mengorganisir content dan assets bersama-sama dalam satu folder. Ini adalah best practice untuk modern content management.
Apa itu Page Bundles?
Definisi
Page Bundle adalah folder yang berisi file content Markdown (biasanya index.md) bersama dengan assets terkait (images, files, data) dalam satu lokasi.
Why Page Bundles?
- Co-location: Assets bersama dengan content
- Resource Management: Akses ke Hugo image processing
- Clarity: Struktur yang jelas dan terorganisir
- Portability: Mudah move content dengan assets-nya
- Version Control: Track changes untuk content + assets
Types of Page Bundles
1. Leaf Bundle (index.md)
Single page dengan resources:
content/posts/my-awesome-post/
βββ index.md # Content file
βββ featured.jpg # Featured image (page resource)
βββ gallery/
β βββ image-1.jpg
β βββ image-2.jpg
β βββ image-3.jpg
βββ diagram.png
βββ attachment.pdf
Frontmatter di index.md:
---
title: "My Awesome Post"
date: 2026-02-03T10:00:00+07:00
draft: false
resources:
- name: featured
src: featured.jpg
params:
credits: "Photo by John Doe"
- name: gallery
src: gallery/**
---
Content goes here...
2. Branch Bundle (_index.md)
Section dengan content dan sub-pages:
content/blog/ # Branch bundle
βββ _index.md # Section content
βββ _index.jpg # Section featured image
βββ my-post-1/ # Leaf bundle
β βββ index.md
β βββ featured.jpg
βββ my-post-2/ # Leaf bundle
βββ index.md
βββ featured.jpg
_index.md:
---
title: "Blog"
description: "Latest articles and tutorials"
cascade:
featured_image: _index.jpg
---
Welcome to our blog!
Resource Management
1. Accessing Resources in Templates
Single resource:
{{ $image := .Resources.GetMatch "featured.jpg" }}
{{ if $image }}
{{ $resized := $image.Resize "800x" }}
<img src="{{ $resized.RelPermalink }}" alt="{{ .Title }}">
{{ end }}
Multiple resources (glob patterns):
{{ $images := .Resources.Match "gallery/*.jpg" }}
<div class="gallery">
{{ range $images }}
{{ $thumb := .Resize "300x200" }}
<img src="{{ $thumb.RelPermalink }}" loading="lazy">
{{ end }}
</div>
By name:
{{ $featured := .Resources.Get "featured" }}
{{ $gallery := .Resources.Match "gallery/**" }}
2. Resource Properties
{{ $image := .Resources.GetMatch "*.jpg" }}
{{ if $image }}
<figure>
<img src="{{ $image.RelPermalink }}"
width="{{ $image.Width }}"
height="{{ $image.Height }}"
alt="{{ $image.Title }}">
<figcaption>
{{ $image.Params.credits }}
({{ $image.Width }}x{{ $image.Height }}px, {{ div $image.Size 1024 }}KB)
</figcaption>
</figure>
{{ end }}
3. Image Processing
{{ $image := .Resources.GetMatch "featured.jpg" }}
{{ if $image }}
{{ $original := $image }}
{{ $resized := $image.Resize "800x webp" }}
{{ $small := $image.Resize "400x webp q60" }}
{{ $large := $image.Resize "1200x webp" }}
<picture>
<source media="(min-width: 800px)" srcset="{{ $large.RelPermalink }}">
<source media="(min-width: 400px)" srcset="{{ $resized.RelPermalink }}">
<img src="{{ $small.RelPermalink }}" alt="{{ .Title }}">
</picture>
{{ end }}
Frontmatter Resource Definitions
1. Named Resources
---
title: "Post Title"
resources:
- name: "header"
src: "images/header.jpg"
title: "Header Image"
params:
credits: "Photo by Jane Doe"
- name: "diagram"
src: "diagram.png"
params:
alt: "System architecture diagram"
- name: "downloads"
src: "downloads/*"
2. Resource Parameters
{{ $header := .Resources.Get "header" }}
{{ if $header }}
{{ with $header.Params.credits }}
<p class="photo-credits">Photo: {{ . }}</p>
{{ end }}
{{ end }}
3. Glob Patterns
---
resources:
- name: "gallery"
src: "gallery/*.jpg"
- name: "all-images"
src: "*
/.jpg"
- name: "documents"
src: "*.pdf"
Practical Examples
Example 1: Blog Post dengan Gallery
Content structure:
content/posts/bali-travel-guide/
βββ index.md
βββ featured.jpg
βββ gallery/
β βββ beach-1.jpg
β βββ beach-2.jpg
β βββ temple.jpg
β βββ sunset.jpg
βββ map.pdf
index.md:
---
title: "Bali Travel Guide: 7 Days Itinerary"
date: 2026-02-03
draft: false
resources:
- name: "featured"
src: "featured.jpg"
params:
caption: "Beautiful sunset at Uluwatu"
-
name: "gallery"
src: "gallery/**"
Explore Bali with this comprehensive 7-day itinerary...
Photo Gallery
{{ < gallery > }}
Download Map
[Download Detailed Map]({{ < resource "map.pdf" > }})
Gallery shortcode:
{{ $images := .Page.Resources.Match "gallery/*" }}
<div class="masonry-grid">
{{ range $images }}
{{ $thumb := .Resize "400x300" }}
{{ $full := .Resize "1200x800" }}
<a href="{{ $full.RelPermalink }}" data-lightbox="gallery">
<img src="{{ $thumb.RelPermalink }}" loading="lazy">
</a>
{{ end }}
</div>
Example 2: Tutorial dengan Code Files
content/tutorials/hugo-basics/
βββ index.md
βββ hugo.toml
βββ config.yaml
βββ tree.txt
index.md:
---
title: "Hugo Basics Tutorial"
type: "tutorial"
resources:
- name: "config-toml"
src: "hugo.toml"
- name: "config-yaml"
src: "config.yaml"
Configuration
TOML Format
{{ < code-file resource="config-toml" lang="toml" > }}
YAML Format
{{ < code-file resource="config-yaml" lang="yaml" > }}
Example 3: Product Page dengan Assets
content/products/software-tool/
βββ index.md
βββ hero.jpg
βββ features/
β βββ screenshot-1.jpg
β βββ screenshot-2.jpg
β βββ screenshot-3.jpg
βββ videos/
β βββ demo.mp4
βββ datasheet.pdf
index.md:
---
title: "Software Tool Pro"
price: 99
resources:
- name: "hero"
src: "hero.jpg"
- name: "screenshots"
src: "features/*.jpg"
- name: "demo-video"
src: "videos/demo.mp4"
- name: "datasheet"
src: "datasheet.pdf"
Product description here...
Cascade dengan Resources
Inheriting Resources di Sections
---
title: "Tutorials"
resources:
- name: "section-banner"
src: "banner.jpg"
cascade:
resources:
- name: "watermark"
src: "../watermark.png"
---
Resources akan tersedia untuk semua pages dalam section.
Content Organization Best Practices
1. Naming Conventions
β
GOOD:
content/posts/
βββ 2026/
β βββ 01-january/
β β βββ my-post/
β β βββ index.md
β β βββ featured.jpg
β βββ 02-february/
β βββ another-post/
β βββ index.md
β βββ featured.jpg
β AVOID:
content/posts/my-post.md
static/images/my-post-image.jpg
2. Asset Organization
content/posts/
βββ my-post/
βββ index.md
βββ featured.jpg
βββ assets/
β βββ diagram-1.png
β βββ diagram-2.png
β βββ chart.svg
βββ downloads/
β βββ whitepaper.pdf
β βββ checklist.pdf
βββ gallery/
βββ photo-1.jpg
βββ photo-2.jpg
βββ photo-3.jpg
3. Resource Metadata
---
resources:
- src: "*.jpg"
name: "photo-{{ .counter }}"
params:
photographer: "John Doe"
license: "CC BY-SA"
---
Troubleshooting
Issue: “Resource not found”
Check:
1. File extension case: .jpg β .JPG
2. Path relatif ke index.md
3. File ada di folder page bundle
# Check resources untuk page
hugo server -D
# Buka: http://localhost:1313/__hugo/resrc/
Issue: “Cannot resize resource”
Pastikan:
– Hugo Extended terinstall
– File adalah image yang valid
– Format supported (JPG, PNG, GIF, WebP)
Issue: “Glob pattern not working”
Gunakan pattern yang benar:
# Benar
resources:
- src: "gallery/*.jpg" # Semua JPG di gallery/
- src: "**/*.jpg" # Semua JPG di semua subfolder
- src: "*.pdf" # Semua PDF di root bundle
Performance Tips
1. Image Optimization
# hugo.toml
[imaging]
quality = 80
resampleFilter = "lanczos"
2. Lazy Loading
<img src="{{ $resized.RelPermalink }}"
loading="lazy"
decoding="async"
alt="{{ .Title }}">
3. Resource Caching
# Hugo caches processed resources
# Clear cache jika perlu:
hugo --gc
Migration ke Page Bundles
From Traditional Structure
Before (Traditional):
content/posts/my-post.md
static/images/posts/my-post/
βββ featured.jpg
βββ gallery/
βββ images.jpg
After (Page Bundle):
# 1. Buat folder
mkdir content/posts/my-post
2. Move content
mv content/posts/my-post.md content/posts/my-post/index.md
3. Move images
mv static/images/posts/my-post/* content/posts/my-post/
4. Update image paths di content
Ganti /images/posts/my-post/ dengan . (relative)
Script untuk Bulk Migration
#!/bin/bash
# migrate-to-bundles.sh
POSTS_DIR="content/posts"
IMAGES_DIR="static/images/posts"
for post in "$POSTS_DIR"/*.md; do
basename=$(basename "$post" .md)
Buat bundle folder
mkdir -p "$POSTS_DIR/$basename"
Move post
mv "$post" "$POSTS_DIR/$basename/index.md"
Move images jika ada
if [ -d "$IMAGES_DIR/$basename" ]; then
mv "$IMAGES_DIR/$basename/"* "$POSTS_DIR/$basename/"
rmdir "$IMAGES_DIR/$basename" 2>/dev/null
fi
done
Kesimpulan
Page Bundles memberikan:
β
Organization: Assets bersama content
β
Portability: Move content dengan semua assets
β
Image Processing: Hugo resources API
β
Version Control: Track semua dalam Git
β
Clarity: Struktur yang jelas dan scalable
Gunakan page bundles untuk semua content baru dan pertimbangkan migrasi content existing untuk better asset management.
Ditulis oleh
Hendra Wijaya