DE

Resource Management in Hugo

Websites use resources such as images, videos, PDFs or other files. Hugo offers a standardized approach as to how these files are organized and integrated on pages using predefined methods and functions.

Global Resources

Some resources are required on the entire website. For example, many websites use the same image as the background in the title area of various subpages. The assets/ directory is suitable in such cases.

Stylesheets (assets/css/) and scripts (assets/js/) are also regarded as assets. That is, Hugo does not make a clear terminological distinction between them and resources in the narrower sense. So-called asset pipelines are often used to minimize the size of such source files.

Page Bundles

So-called page bundles are an important tool for resource management. The term refers to directories that can contain both markup files and associated resources. Hugo distinguishes between Leaf Bundles and Branch Bundles.

It is not uncommon for resources to be used only once and only on one specific page. In these cases, it makes sense to store them directly with the corresponding markup file. This is precisely the purpose of Leaf Bundles. Instead of creating a single file for a main content (e.g. content/.../example-name.md), a directory is created for a leaf bundle that contains the file content/.../example-name/index.md. Externally, everything remains the same: the site can be accessed as before at domain.com/example-name/.

The difference is that now we can store additional files in the example-name/ subdirectory that we want to use on the corresponding page. It is up to you how you want to structure the directory. An image, for instance, could be stored under content/.../example-name/images/image-1.png.

Branch bundles are used in cases where several pages of a section access shared resources. This is possible if an _index.md is created in a directory. Additional resources can again be stored in these directories and then be included in the markup files using the predefined methods.

How to Insert Resources on Pages

Image resources from page bundles can be included in Markdown with the following syntax:

![alt-text](file "title")

Hugo automatically converts these constructs into HTML:

<img src="file" alt="alt-text" title="title">

A more flexible use of image resources is possible with shortcodes. To do this, we may first define a partial layout under layouts/partials/render-image.html, which also supports image captchas:

{{- $imageURL := .image }}
{{- $altText := .alt | default "" }}
{{- $caption := .caption | default "" }}

<figure class="image-figure">
  <picture>
    <img
      src="{{ $imageURL }}"
      alt="{{ $altText }}"
      loading="lazy"
    >
  </picture>
  {{ with $caption }}
    <figcaption>{{ . | markdownify }}</figcaption>
  {{ end }}
</figure>

A shortcode for images that come directly from page bundles could now be defined under shortcodes/images/insert-image.html:

{{- $image := .Get 0 }}
{{- $altText := .Get 1 }}
{{- $caption := .Get 2 }}

{{- $pageURL := .Page.RelPermalink }}
{{- $imageURL := printf "%s%s" $pageURL $image }}

{{ partial "images/render-image.html" (dict "image" $imageURL "alt" $altText "caption" $caption) }}

This shortcode uses the image resource relative to the page path, supplements it with alt text and caption, and transfers the data to the previously defined partial layout.

To insert images from a global folder (by default assets/images), another shortcode can be created that loads resources via resources.Get:

{{- $image := .Get 0 }}
{{- $altText := .Get 1 }}
{{- $caption := .Get 2 }}

{{- $imageResource := resources.Get (printf "images/%s" $image) }}

{{- if not $imageResource }}
  {{ errorf "Image '%s' not found in assets/images/" $image }}
{{- end }}

{{ partial "images/render-image.html" (dict "image" $imageResource.Permalink "alt" $altText "caption" $caption) }}

This shortcode checks whether the image resource exists and transfers the absolute URL and other metadata to the partial layout. Resources of other types could be inserted in a similar way.

Branch Bundles and Sections

As already mentioned, directories are considered branch bundles if they contain an _index.md. For this reason, each branch bundle is a section and hence includes an overview page. The idea is perhaps: If contents access the same resources, then they somehow belong together. In other words, they are part of one section.

If you want to prevent the listing behavior, you can define a layout for this purpose, for instance as layouts/_default/non-listing.html:

{{ define "main" }}
   <article class="page">
       <header>
           <h1>{{ .Title }}</h1>
       </header>
       <div class="content">
           {{ .Content }}
       </div>
   </article>
{{ end }}

To apply the layout, it is explicitly selected in the frontmatter of the corresponding _index.md:

---
layout: non-listing
---

Article from September 27, 2024.