Wilson E. Husin

Underrated Hugo features

December 11, 2022 (UTC)

The site you are reading now is generated by Hugo (oh, and the source code for this site is open-source). I have had a generally pleasant time managing Hugo-based static site for the last few years.

I also found that it has plenty of hidden gems (wink Jekyll wink) — some really should have been the default behavior.

Image resizing (and WebP conversion) ¶

Hugo has built in support for resizing and WebP conversion, which can be invoked by calling .Resize. Here is a sample from the documentation about image processing:

{{ with .Resources.GetMatch "sunset.jpg" }}
  {{ with .Resize (printf "%dx%d webp" .Width .Height) }}
    <img src="{{ .RelPermalink }}" width="{{ .Width }}" height="{{ .Height }}">
  {{ end }}
{{ end }}

Refer to documentation on Page Resources to learn more about the .Resource usage.

Markdown render hooks ¶

By default, links generated by Hugo will open in the same browser page. However, Hugo allows you to customize it through invoking Markdown render hooks and add the target="_blank" conditional yourself. I think this deserves to be default behavior.

<!-- layouts/_default/_markup/render-link.html -->
<a
  href="{{ .Destination | safeURL }}"
  {{ with .Title }}title="{{ . }}"{{ end }}
  {{ if strings.HasPrefix .Destination "http" }}
    target="_blank" rel="noopener"
  {{ end }}
  >
  {{- .Text | safeHTML -}}
</a>

Additionally, Hugo also supports overriding # conversion to <h1> (and its variances). Useful for adding anchors.

Truncating extra line / space ¶

If you use Hugo shortcodes for inline text, you may notice an extra space or newline being added automatically after the shortcode invocation. This is typically a problem in *nix-based systems where every file ends with newline, and Hugo process them literally.

To mitigate this, add dashes within your shortcode invocation, i.e. {{- myshortcode -}} as Hugo honors Go’s templating behavior. Alternatively, you may also append the end of shortcode template file with {{- print "" -}}.

Dynamic syntax highlighting ¶

Hugo internally relies on Chroma to add syntax highlighting on codeblocks. Conveniently, Chroma comes with plenty of popular syntax highlighting themes. Chroma also provides a playground though the options are not exhaustive of all available themes / styles. The fact that such a feature is built in means we don’t need to invoke something like PrismJS.

Now here is the tricky part: if your site supports dark and light mode, a given syntax highlight color may only play along with one mode but not the other. At the cost of a few more kilobytes being transferred over the network, you can extract the syntax highlighting system to a CSS file, then set markup.highlight.noClasses = false in config.toml.

For example, this site uses gruvbox theme, where it’s more friendly to dark mode pages. Chroma also has gruvbox-light for the light mode counterpart. HTML allows conditional load of different assets based on prefers-color-scheme, which allowed me to load different Chroma styles.

 1<head>
 2  <link
 3    rel="stylesheet"
 4    href="/css/syntax/gruvbox-dark.css"
 5    media="(prefers-color-scheme: dark)"
 6  />
 7  <link
 8    rel="stylesheet"
 9    href="/css/syntax/gruvbox-light.css"
10    media="(prefers-color-scheme: light)"
11  />
12</head>

Remember to update markup.highlight.noClasses on config.toml.

[markup]
  [markup.highlight]
    noClasses = false