Creating a Website with Hugo

Automation never seems to find the end of the road. When you think something routine can’t be automated in another way, BAM!, here it comes. Hugo is a static site generator that uses the “Go” lanuguage - a “markdown” language. It was developed by Steve Francia in 2013 and continued development by Bjørn Erik Pedersen since 2015. Hugo is a system that takes tagged text (aka “markdown”) and creates a static (meaning that webpages are not created on the fly generally by software running on the web server that dynamically formats the HTML sent to the browser, but does not change) web pages. This article gives an overview of my experience developing this website using Hugo. Hugo’s home is at https://gohugo.io/.

Overview

Hugo

I read this article on How-to-Geek and was intrigued by the concept of producing a static website without the hassle of coding HTML5 markup, fiddle-farting around with the related CSS. This is how I created this website using Hugo software framework and the Go markdown language. I’ve been quite impressed with its simplicity and my ability to concentrate on the content. I really like the feature for initiating a pseudo web server that dynamically rebuilds the static pages that you can view in a web browser as you save content in a file along with integration into GitHub.

I started with Youtube videos to get a jump on the basics for developing my website using Hugo. Most of what I watched were produced by Chris Stayte and Mike Dane. I used these references in getting started:

Prerequisites

  1. Opened account at https://github.com. Installed the Git package on my Fedora desktop.
sudo dnf install git

I also set up my project on GitHub.

  1. Installed Hugo package on my Fedora desktop
sudo dnf install hugo
  1. Downloaded the atom workbench package from (https://atom.io) and installed it.
sudo dnf install atom.x86_64.rpm

I played with atom a bit, but wound up just text editing the file from the command line using the vi editor. Gedit might be more flexible to use due to positioning within a paragraph is difficult using vi.

Setup Website Project for Hugo

cd /path/to/hugo.devlt
hugo new site awolfe.info
cd awolfe.info
git init
git add .
git status

Installed Theme

The Docsy installation guide gave instructions for installing hugo-extended and a couple other packages. The Hugo package on Fedora contained the “extended” feature set and did not need the other packages mentioned to be installed. I wound up needing npm, but I installed it later.

cd /path/to/hugo.devlt/awolfe.info/themes
git clone --recurse-submodules --depth 1 https://github.com/google/docsy.git

To test the theme installation I did:

cd docsy/userguide
hugo server --themesDir ../..

When the Hugo server started, it listed a table of how many pages were built and gave me the URL to access the website. I was able to verify the example (userguide) worked though Hugo but it complained over:

found no layout file for "JSON" for kind `home`:  You should create a template file which matches Hugo layouts Lookup Rules for this combination.

This issue was due to the config.toml file not needing the JSON on the “home” spec.

[CTL]-C on the command line stops the Hugo server. Starting off, I had two instances of Hugo server running. The first starts up on port 1313 with the second one starting on some random port. After running the server for a while, or when I encounter some odd issue, I found I had to kill the server and restart it to correct the issue.

Initial Configuration of My Website

NOTE

Hugo’s configuration begins with the config.toml file and certain subdirectories. Hugo is fueled primarily by the themes installation. If you need to modify some component in the “themes” directory, you copy it out to your website project directory and modify it. Anything in your website project subdirectories overrides what is in the “themes” directory. This is purposeful, in that having the theme cloned from its project source at GitHub, you withstand a future update of the theme tromping over your modifications.

To start off, I copied the config.toml file from out of the userguide directory from the Docsy theme into my website configuration. I then changed the obvious suspects.

baseURL = "/"
title = "Allan Wolfe"
themes = ["docsy"]

Creating Menu Structure and Articles

Optionally, you can modify the default front matter template at archetypes/default.md. You can create a new page by:

hugo new pagename.md

I wound up just copying an _index.md and going at it for the next page.

NOTE

Hugo looks for an _index.html in the root directory of your content directory. The root page is treated differently than the subordinate pages. For each section, there is an _index.md file in the subdirectory that supports your section landing page.

The structure of your website is defined in terms of a subdirectory structure, each with an _index.md or index.md in its directory. (I found with the Docsy theme, only the _index.md formatted the page correctly.) You create a subdirectory as you organize multiple articles displayed on a single section page. Those .md (markdown) files are named something other than _index.md or index.md.

My default markdown file looked something like this for top menu level:

---
title: "Blue Skies"
linkTitle: "Blue Skies"
date: 2018-02-15
menu:
  main:
    weight: 10
---

and this for sub sections and articles:

---
title: "Some Prolific Article"
linkTitle: "Some Prolific Article"
weight: 100
date: 2021-02-16
description: >
  Some description to appear on the referencing page and in the article.
---

NOTE

I saw the term “front matter” used. I learned that this term originated with the idea of writing a book. Front matter in book publishing means simply the first sections of the book such as the title page, copyright page and table of contents. “Back matter” means those sections at the end of a book such as the index or appendix. Front matter here is merely a reference to the YAML header of a markdown file (i.e. the key/value pairs between the “---” markers.

NOTE

It is worth mentioning that the markdown files can be in the TOML, JSON or ORG format. The difference is the use of delimiters.

All of the contents of the article is placed below the second “---” marker. Go will recognize either HTML markup or Go markdown notation in the content area below the second “---” marker. This is a really great flexible feature. You present the content in the easiest way possible and only complicate it as needed (eg, inserting in markup for audio control to embed playing an audio file). The Go language doesn’t provide for all of what you can do in HTML markup but is preferred when possible – K.I.S.S. (keep it simple stupid) principle.

One frustration I had was figuring out why the format of my pages were not what I saw in the Docsy example code. Since I went with my own menu item names, I had to copy out the particular themes/docsy/layouts subdirectory for the format I wanted into my project’s layout with the directory name the same as the menu item directory name.

For the document based menu items, I copied over themes/docsy/layouts/docs directory. Since the “Blog” was the same name as what was defined in the theme layout, I didn’t need to copy it over.

cd /path/to/hugo.devlt/awolfe.info
cp -R ./themes/layouts/docs ./layouts/technology

The static directory is reserved for files that are referenced but not interpreted (e.g. image files, but no markdown or HTML files). You can create subdirectories to better organize such things as image or pdf files for inclusion in your markdown or for download. In your markdown, you can referentially reference these files beginning with “/” followed by the subdirectory you created. “static” is not in the path of your relative reference.

Another feature of Go/Hugo is the ability to create your own code snippets called “shortcodes”. Shortcodes are stored at layouts/shortcodes and referenced in your markdown using double curly brackets. See the Hugo documentation for more information.

Enabling the Search Function

Of all the work done to stand up my website, enabling search was the most confusing. Hugo provides some built-in integration with some commercial search engines for the private space such as Google’s GCSE or Algolia. I chose to go with Lunr.js since my web server is small and I didn’t want to tax it with cranking out search results. I preferred to decentralize it to the client since my index file would be relatively small. Hugo provides support for Lunr.js, but the documentation could be improved. There is also a dependancy here on the theme implements the function. I used the Docsy theme and it had its own documentation that provided some different perspective on how it integrated search into its theme and how to configure for it. Here is what I did to get it to work for me.

First, NPM (a javascript package manager) is needed to be installed in order to install certain packages that Hugo needs for producing an index file for downloading to the client. (I also found it needed some additional packages to publish the static content).

On Fedora Linux:

sudo dnf install -y gcc c++ make
curl -sL https://rpm.nodesource.com/setup_10.x | sudo -E bash -
sudo dnf install npm
node -v      ## check that node installed correctly
npm -v       ## check that npm installed correctly

Gulp was needed to generate the index in JSON format. To install Gulp:

sudo npm install gulp-cli -g
gulp -v      ## Check that gulp installed and functions

Modified the Hugo project config.toml:

cd /path/to/hugo.devlt/awolfe.info
vi config.toml

Commented out the GCSE ID, turning off Algolia and enabling lunr.js:

# Google Custom Search Engine ID. Remove or comment out to disable search.
#gcs_engine_id = "011217106833237091527:la2vtv2emlw"

# Enable Algolia DocSearch
algolia_docsearch = false

# Enable local search (i.e. client side search using lunr.js))
offlineSearch = true
offlineSearchMacResults = 25

Gulp is used to create the search***.json file in the build of the /public static files. The guides I read instructed to manually run Gulp before compiling the static files with Hugo. It wasn’t worth the effort to manually create the index search file since Hugo does that as part of the build process anyway.

Build Static Pages

Publishing the static pages was fairly simple. I experienced some whining out of Hugo that required adding some extra packages using npm to install them.

cd /path/to/hugo.devlt/awolfe.info
npm --save-dev gulp postcss postcss-cli autoprefixer hugo-search-index
hugo 

The output defaults to a ./public directory. The npm --save-dev saves the package to the project directory node_modules directory. In trying to install globally produced some errors that I didn’t have just installing locally. I’m not creating multiple websites anyway.

After publishing, starting the Hugo server again, I tested the search feature and reviewed the structure and content of my web site before copying the /public directory to my web server.

GitHub Push

Update your GitHub repository:

cd /path/to/hugo.devlt/awolfe.info
git push -u origin myproject

Final Notes

  • If you wish to exclude a page from the search index file, add this line to the front matter of the .md file:

exclude_search: true

  • If you wish to mark an article as “draft”:
draft: true

Other References

Ecommerce on Hugo

Photo Gallery in Hugo

Last modified February 25, 2021: version 2.0 (70b449f)