+++
date = "2022-03-30T21:21:29+00:00"
publishdate = "2023-12-29T07:08:55+00:00"
title = "Hugo is Good"
slug = "hugo-is-good"
author = "Thedro"
tags = ["hugo"]
type = "posts"
summary = "Hugo is a static site generator program and a mighty good piece of free software."
draft = ""
syntax = "1"
toc = ""
updated = "2022-04-03"
+++
![Hugo's landing page](/images/mixing-php-into-hugo.png "
Hugo's [homepage](https://gohugo.io/)."
)
[Hugo](https://gohugo.io/) 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](https://www.thedroneely.com/posts/mixing-php-into-hugo/)
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](https://www.maximumethics.dev/blog/2021/03/smart-quotes/)
--- it's great to see a lot of interesting details resolved. The
[Goldmark Markdown](https://github.com/yuin/goldmark#readme)
{{< sidenote mark="parser"
set="left" >}} [CommonMark](https://commonmark.org/) compliant, the proposition of
a highly compatible specification of [Markdown](https://en.wikipedia.org/wiki/Markdown).
{{< /sidenote>}} is clean.
If you're [early adopting](https://en.wikipedia.org/wiki/Early_adopter)
software, sometimes you've got to take a primitive approach to using its
interfaces since
[future changes may catch up to you](https://harrycresswell.com/writing/breaking-changes-upgrading-hugo/)
in {{< sidenote mark="varying" set="right" >}} It's difficult to experience big
breaking changes with `hugo` though --- the update paths are forgiving.
{{< /sidenote>}} degrees. I'm now on `hugo` version `0.94.2` and have extricated
myself from a myriad of hacks with {{< sidenote mark="little" set="left" >}} My
premises begin with the notion that all software is unreliable and frustrating.
{{< /sidenote>}} effort. Writing posts in `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](https://micro.thedroneely.com/m/tags/docs/) `hugo` [
theme](https://www.thedroneely.com/git/thedroneely/canory/) which uses semantic
[`HTML`](https://en.wikipedia.org/wiki/HTML) (HyperText Markup Language)
explores more of the specific features discussed below.
## Markdown
The [text file](https://en.wikipedia.org/wiki/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](https://commonmark.org/help/) text
file that is transformed. You can {{< sidenote mark="view" set="right" >}} At the
bottom of each article is a link to the `markdown` source file. {{< /sidenote>}}
[the raw text file](https://www.thedroneely.com/posts/hugo-is-good.md) that my
system transforms to see the underlying `markdown` format for this article.
## Diagrams
If desired, diagrams can be drawn on the fly as an
[`ASCII`](https://en.wikipedia.org/wiki/ASCII) (American Standard Code for
Information Interchange) representation using
the [GoAT](https://github.com/blampe/goat#readme) --- the [`Go`](https://go.dev/doc/)
`ASCII` tool built into `hugo`. The `ASCII` representation is rendered to
[`SVG`](https://en.wikipedia.org/wiki/Scalable_Vector_Graphics) (Scalable Vector
Graphics). You can also shim in the more popular
[Mermaid](https://github.com/mermaid-js/mermaid#readme) diagrams using
[render `code` block hooks](https://gohugo.io/content-management/diagrams/#mermaid-diagrams)
and [`JavaScript`](https://en.wikipedia.org/wiki/JavaScript) includes.
Drawing this for the first time was an interesting fiddle and dance with the
[`vim`](https://www.vim.org/) editor. There are tools like
[ASCIIFlow](https://asciiflow.com/#/)
([repository](https://github.com/lewish/asciiflow#readme)) that makes this sort
of thing quicker, but [Emacs](https://www.gnu.org/software/emacs/) in
[artist mode](https://www.youtube.com/watch?v=cIuX87Xo8Fc) is probably the
{{< sidenote mark="fastest" set="left" >}} Emacs tends to have a lot of peculiar
modes.
[Diff mode](https://www.gnu.org/software/emacs/manual/html_node/emacs/Diff-Mode.html)
is one of my favorites.{{< /sidenote>}} way.
```goat {caption="My first attempt at arbitrarily mapping how hugo generates the static parts of my website."}
+-------------------. .-> thedroneely.com/posts/hugo-is-good/
| hugo | .--> public ---+
'---------+---------' | '-> thedroneely.com/images/placeholder.png/
| |
.-----------.------------. |
| | | '---.
| | | | .---- baseof.html ---> "Base Template"
config.toml config.yaml config.json | |
| | | | +----- single.html ---> "Article Content"
| | | | |
'-----------+------------' '-. +----- section.html --> "Article Card"
| | .---+
.------------' '--------------------+---+. | +----- list.html -----> "List of Article Cards"
| .| | | |
+---> content/posts/hugo-is-good.md --->| | | +----- rss.xml -------> "RSS Feed"
| | | | |
++--> resources/_gen --------------. | | | '---- sitemap.xml ---> "Site Map"
| | | | |
+'--> assets/images/placeholder.png '->| | |
| ^ | |
+---> themes/tdro/layouts/_default <---+-+-'
| |
'----------------------------------------'
```
## Configuration Formats
Hugo makes use of [`TOML`](https://toml.io/en/) (Tom's Obvious Minimal
Language), [`YAML`](https://yaml.org/) (`YAML` Ain't Markup Language), and
[`JSON`](https://www.json.org/json-en.html) (JavaScript Object Notation) as
configuration formats for itself and its
[front matter data](https://gohugo.io/content-management/front-matter/). `YAML`
is probably the most popular format but `hugo` favours
{{< sidenote mark="`TOML`" set="right" >}} `TOML` is my favorite.
{{< /sidenote>}} .
In the [front matter](https://gohugo.io/content-management/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 {options="hl_lines=34-42 44-45 47 51-53 58-62"}
---
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](https://github.com/alecthomas/chroma#readme) for syntax highlighting
which is based on the [Pygments](https://pygments.org/)
[Python](https://www.python.org/) syntax highlighter. Chroma supports a wide
variety of languages and you can highlight specific lines.
```yaml {options="hl_lines=2"}
---
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](https://github.com/tdro/thedroneely.com/blob/cbf66d935d1952e52ca47997bcadd108257f1cda/public/css/syntax-highlight.css)
to colorize the tokens. No need to pull out the `JavaScript` hammer for code
syntax highlighting.
## Short Codes
[Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugos-built-in-shortcodes)
allow for creating micro templates that are
{{< sidenote mark="weaved" set="left" >}} My content uses somewhat wieldly short
codes for side notes that are based on a modified version of Dave Liepmann's
[Tufte `CSS`](https://edwardtufte.github.io/tufte-css/).{{< /sidenote>}}
throughout a `markdown` text file. Hugo
[provides](https://github.com/gohugoio/hugo/tree/master/tpl/tplimpl/embedded/templates/shortcodes)
a set of
[built--in shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugos-built-in-shortcodes)
for popular sites around the web. If you want, you could embed a
[GitHub Gist](https://gist.github.com/discover) with a short code.
{{< gist spf13 7896402 >}}
## Render Hooks
[Render hooks](https://gohugo.io/templates/render-hooks/) let `hugo` change
specific `markdown` rendering behavior. For example, `HTML` output for
[section headings](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements)
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
{{ .Text | safeHTML }}
```
## Output Formats
The [custom output format](https://gohugo.io/templates/output-formats/) is the
_most_ important feature in my opinion. If you take a look at
[the configuration file](#configuration-formats) 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`
{{< sidenote mark="feed" set="right" >}} The proposition of the
[`JSON` Feed](https://www.jsonfeed.org/version/1.1/) --- a syndication format that is
like [`RSS`](https://en.wikipedia.org/wiki/RSS) and
[Atom](). {{< /sidenote>}}
using [Hugo's extension](https://godocs.io/github.com/gohugoio/hugo/tpl) of the
[`go` template](https://godocs.io/text/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`](/index.json) 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](https://en.wikipedia.org/wiki/Headless_content_management_system)
and in the wider marketing sphere, "[JAMStack](https://jamstack.org/)".
For example, this article can be comfortably edited using the
{{< sideimage mark="`vim`" set="left" source="/images/writing-with-vale.png" >}}
Editing an article in the `vim` editor. {{< /sideimage >}} editor or through a
{{< sideimage mark="web" set="right" source="/images/cockpit-cms-post.png" >}}
Editing an article in the Cockpit `CMS` dashboard. {{< /sideimage >}} based
content management system like [Cockpit `CMS`](https://getcockpit.com/). If
you're clever enough, you can contort anything to act as your "headless" `CMS` (even utterly horrific content management systems (`CMS`) like
[WordPress](https://github.com/WordPress/wordpress-develop#readme)) since a
headless `CMS` at its source exposes an extremely flexible
[`API`](https://en.wikipedia.org/wiki/API) (Application Programming Interface).
A lot of [headless `CMS` options](https://jamstack.org/headless-cms/)
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](https://gohugo.io/hugo-modules/use-modules/). Hugo modules tap
into the general [`go` module ecosystem](https://go.dev/blog/using-go-modules),
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](https://www.thenewdynamic.com/article/hugo-modules-everything-from-imports-to-create/).