Hugo is Good
Hugo is a static site generator program and a mighty good
piece of free software. This blog has been mostly powered by hugo
since about 4
years ago
beginning with version 0.44
. Usually, my summary description of hugo
is that
it’s a blog templating system, but hugo
has enough generality and versatility
to be called a data templating system.
Lately, I’ve been catching up to some of its newer features, and after
revisiting conundrums like the
smart quotes edge cases
— it’s great to see a lot of interesting details resolved. The
Goldmark Markdown
If you’re early adopting
software, sometimes you’ve got to take a primitive approach to using its
interfaces since
future changes may catch up to you
in hugo
though — the update paths are forgiving.
hugo
version 0.94.2
and have extricated
myself from a myriad of hacks with markdown
was already easy, but now
it’s even easier?
Let’s take a look at features this random blog uses or could use from Hugo’s
feature set. In order not to make this too long, my micro
blog hugo
theme which uses semantic
HTML
(HyperText Markup Language)
explores more of the specific features discussed below.
Markdown
The text file is king. Form separated
from content, and content edited from a plurality of user interfaces —
graphical or otherwise is hard to beat in my opinion. This article’s single
source of truth is a Markdown text
file that is transformed. You can markdown
source file.
markdown
format for this article.
Diagrams
If desired, diagrams can be drawn on the fly as an
ASCII
(American Standard Code for
Information Interchange) representation using
the GoAT — the Go
ASCII
tool built into hugo
. The ASCII
representation is rendered to
SVG
(Scalable Vector
Graphics). You can also shim in the more popular
Mermaid diagrams using
render code
block hooks
and JavaScript
includes.
Drawing this for the first time was an interesting fiddle and dance with the
vim
editor. There are tools like
ASCIIFlow
(repository) that makes this sort
of thing quicker, but Emacs in
artist mode is probably the
Configuration Formats
Hugo makes use of TOML
(Tom’s Obvious Minimal
Language), YAML
(YAML
Ain’t Markup Language), and
JSON
(JavaScript Object Notation) as
configuration formats for itself and its
front matter data. YAML
is probably the most popular format but hugo
favours
TOML
is my favorite.
In the front matter,
TOML
uses +++
delimiters, YAML
, ---
delimiters, and JSON
{}
delimiters. The typical hugo
configuration can configure many options, and you
can add pretty much anything to the config.toml
, config.yaml
, or
config.json
file.
yaml
---
baseURL:
theme: base
title: Base
languageCode: en-us
author:
name: Opulene
menu:
main:
- name: Home
url: /
weight: 1
- name: Data
url: /data/
weight: 2
- name: Tags
url: /tags/
weight: 3
- name: Archives
url: /archives/
weight: 4
- name: JSON Feed
url: /index.json
weight: 5
- name: RSS
url: /rss.xml
weight: 6
paginate: 1
summaryLength: 20
markup:
highlight:
anchorLineNos: true
codeFences: true
guessSyntax: true
lineNos: false
lineNumbersInTable: false
noClasses: false
noHl: false
taxonomies:
tag: tags
outputFormats:
html:
baseName: index
mediaType: text/html
json:
baseName: index
mediaType: application/json
rss:
baseName: rss
mediaType: application/xml
outputs:
home:
- html
- rss
- json
section:
- html
- rss
taxonomy:
- html
- rss
term:
- html
- rss
page:
- html
By default, hugo
sets up logic for tag and category taxonomies but tags are
usually good enough for most people. Categories can be hidden with the
taxonomies
key as seen in the above code block by only showing tags.
Code Fences and Syntax Highlighting
Speaking of code blocks, hugo
allows for a lot of flexibility when rendering
code syntax highlighting. Hugo uses
Chroma for syntax highlighting
which is based on the Pygments
Python syntax highlighter. Chroma supports a wide
variety of languages and you can highlight specific lines.
yaml
---
markup:
highlight:
anchorLineNos: true
codeFences: true
guessSyntax: true
lineNos: false
lineNumbersInTable: false
noClasses: false
noHl: false
You can even configure hugo
to generate class based tokens on the HTML
output and use
a separate CSS
style sheet
to colorize the tokens. No need to pull out the JavaScript
hammer for code
syntax highlighting.
Short Codes
Shortcodes
allow for creating micro templates that are
CSS
.
markdown
text file. Hugo
provides
a set of
built–in shortcodes
for popular sites around the web. If you want, you could embed a
GitHub Gist with a short code.
Render Hooks
Render hooks let hugo
change
specific markdown
rendering behavior. For example, HTML
output for
section headings
can be changed by altering the markup in
layouts/_default/_markup/render-heading.html
. This is a handy feature for
controlling specific HTML
output across the entire layout.
go-html-template
<h{{ .Level }} id="{{ .Anchor | safeURL }}">
<a
title="{{ .Text | safeHTML }}"
href="#{{ .Anchor | safeURL }}">
{{ .Text | safeHTML }}
</a>
</h{{ .Level }}>
Output Formats
The custom output format is the
most important feature in my opinion. If you take a look at
the configuration file above, you’ll see that hugo
can be parked onto multiple data types. HTML
is not the only format you can
work with — it can be anything.
For example, it’s not too hard to get a bit barbaric and forge a JSON
JSON
Feed — a syndication format that is
like RSS
and
Atom.
go
template at
layouts/_default/index.json
.
go-html-template
{
"version": "https://jsonfeed.org/version/1.1",
"title": "{{ .Site.Title }}",
"home_page_url": "{{ .Site.BaseURL }}",
"feed_url": "{{ .Site.BaseURL }}/index.json",
"items": [
{{- range $index, $data := where .Site.RegularPages ".Params.hidden" "!=" "true" -}}
{{- if ne $data.Type "json" -}}
{{- if and $index (gt $index 0) -}},{{- end }}
{
"id": "{{ md5 $data.Permalink }}",
"url": "{{ $data.Permalink }}",
"title": {{ $data.Summary | htmlUnescape | jsonify }},
"summary": {{ $data.Summary | htmlUnescape | jsonify }},
"date_modified": "{{ $data.Date | time.Format "2006-01-02T15:04:05Z" }}",
"date_published": "{{ $data.PublishDate | time.Format "2006-01-02T15:04:05Z" }}",
"_metadata": {
"slug": "{{ $data.Slug }}",
"type": "{{ $data.Type }}"
},
"author": {
"name": "{{ .Site.Author.name }}"
},
"tags": [
{{- range $tags, $tag := $data.Params.tags -}}
{{- if $tags -}}
,
{{- end -}}
"
{{- $tag | htmlEscape -}}
"
{{- end -}}
],
"content_text": {{ $data.Plain | jsonify }},
"content_html": {{ $data.Content | jsonify }}
}
{{- end -}}
{{ end }}
]
}
Now my site now has a JSON Feed
outlet that could be useful on
the client side.
Headless Content Management
Static site generators in general offer the flexibility of using any administrative or presentation interface as the front end. This decoupling of the front from the back is sometimes called a headless content management system and in the wider marketing sphere, “JAMStack”.
For example, this article can be comfortably edited using the
vim
editor.
CMS
dashboard.
CMS
. If
you’re clever enough, you can contort anything to act as your “headless” CMS
(even utterly horrific content management systems (CMS
) like
WordPress) since a
headless CMS
at its source exposes an extremely flexible
API
(Application Programming Interface).
A lot of headless CMS
options
are out there.
Conclusion
Hugo is a good static site generator, and has a lot of interesting use cases —
hopefully, at some point I’ll take a closer look into
hugo
modules. Hugo modules tap
into the general go
module ecosystem,
allowing you to mount the contents of modules as file directories or import them
for use inside your project. Check out this article on the
hugo
module system.