Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active March 11, 2021 00:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfkaye/e37d158895f0d4ffe9e7fe360c513253 to your computer and use it in GitHub Desktop.
Save dfkaye/e37d158895f0d4ffe9e7fe360c513253 to your computer and use it in GitHub Desktop.
Switching to the Hugo static site generator - reasons, resources, more

Sept 21, 2020: Now a blog post at https://dfkaye.com/posts/2020/05/22/switching-to-hugo-reasons-resources-and-more/

Switching to the Hugo static site generator - reasons, resources, more

Lists

I maintain a couple of github repositories which are nothing more than lists of interesting developer related links. This is one has been growing for nearly 5 years and I felt it was time to cut over to a an active list in a static site I could run a link checker on... et cetera.

Demos

I wanted to create a few working demos (CSS-only tabs, for example, or an aria-accessible modal with some JavaScript), and found that my free Wordpress instance (at https://dfkaye.wordpress.com) does not allow static JavaScript or inline JavaScript tags. A paid plan allows for that, but I wanted to see about alternatives.

So what happened?

Due to the hype in 2019 and a recommendation from a colleague, I started migrating my blog to Gatsby. After generating the basic blog from a starter project (and hooking up Netlify with github), I was dismayed to find that importing specific JavaScript files into posts works in GatsbyJS only when you enter the page URL directly in the browser — without loading the whole blog first. When you load the blog and navigate by hyperlinks controlled by ReactJS routing, the external JavaScript files and inline JavaScript elements fail to load because React scrubs them - see more about that at gatsbyjs/gatsby#833.

All of which tells us...

Gatsby is not a static site generator

Yes, Gatsby uses ReactJS on the server to create, not a static site, but a Single Page Application (SPA) using ReactJS on the client. Unless you are hosting a page that must handle multiple views of a single data source, SPAs have enormous accessibility and performance limitations, as witness Adam Silver's 2014 post, The disadvantages of single page applications.

And so...

After further searching (and emailing Chris Ferdinandi of the "Go Make Things" blog), I decided on Hugo, a static site generator written in the go programming language. Hugo supports HTML, CSS, JavaScript, markdown, and several others without a client-side framework getting in the way.

Other articles on this topic

Big collection of resources

Awesome Hugo has a massive list of articles and resources for Hugo.

Book recommendation

Brian Hogan (2020), Build Websites with Hugo - via bookshop.org.

Highly recommend Brian's approach that introduces you to concepts as you need them rather than give you everything at once.

Things I found helpful

I wanted to cover a lot of bases before beginning the whole migration. Here's a spread out list:

Installing On Windows 10

YouTube

Watch the whole Hugo Tutorial series on YouTube by Mike Dane.

This series of 23 videos - about 5–10 minutes each - covers the basics of installing Hugo, explaining content, themes, templates, shortcodes, etc.

Starter projects

Documentation

Hugo documentation steps are everywhere.

Probably the best single post that covers almost everything

Screen reader support

Themes

Themes are not strictly necessary, but they are shareable. You do one of the following:

Raw HTML

Insert raw html into markdown with shortcode.

RSS feed

Hugo generates its own RSS XML, here's how to include it in the <head> tag → https://gohugo.io/templates/rss/#the-embedded-rss-xml

Menus

Start with Menu templates on the Hugo site → https://gohugo.io/templates/menu-templates/

Pagination

Different ways to tackle pagination links.

Security headers on Netlify (excluding CSP)

Content Security Policy

Different ways to creates Content Security Policy (CSP) headers in Hugo.

First, check https://exploited.cz/xss/csp/strict.php for script-src "strict-dynamic" support in your browser.

Then

Comments

SEO

Sitemap

Hugo documentation on the sitemap template → https://gohugo.io/templates/sitemap-template/

URL management

Permalinks, aliases, canonical URLs → https://gohugo.io/content-management/urls/

Handling Builds beyond the basic hugo commands

You can use npm scripts for building and deploying Hugo sites → https://www.aerobatic.com/blog/hugo-npm-buildtool-setup/

Newsletters

Social Sharing buttons

Syntax highlighting

Hugo comes with really fast syntax highlighting from Chroma... → https://gohugo.io/content-management/syntax-highlighting/

Search

See Chris Ferdinandi's site for

See also Phil Hawksworth, Adding search to a JAMstack Sitehttps://www.hawksworx.com/blog/adding-search-to-a-jamstack-site/

Visuals

Mermaid diagrams

SVG icons

Some blog layouts worth considering

Troubleshooting Hugo

Sept 21, 2020: Now a blog post at https://dfkaye.com/posts/2020/05/23/switching-to-hugo-steps-sequence-troubleshooting/

Making the switch

Not tedious, but there's a sequence. Here's what I did.

Use an installer

I use Windows 10 on a Dell laptop, so I use chocolatey. On a macOS I would use homebrew.

  1. Install chocolatey (run as admin)
  2. Install hugo using chocolatey
  3. Verify on the command line that hugo is installed by typing hugo version.

Create the project

  1. Create/navigate to the directory that will serve as the parent for your hugo site. For example, if you plan to work from C:\projects\hugo-blog, go to C:\projects.
  2. Execute hugo new site <blog-name> from there to generate the <blog-name> directory with the hugo static site scaffolding.

Connect to github

Don't wait. Get this under git immediately.

Create the repository on github.

Then navigate to your local blog directory and type git init.

Connect the repo to your host provider

Do this next. Don't wait. I use netlify.

Stick with the default URL they give you at first.

Buy a domain name when you're comfortable with the build cycle.

Create a home page template

Create an HTML file at layouts/index.html. See Zach Betz's post for a nice example.

Push a change to git master

  1. Add all the files to git: git add .
  2. Commit your changes: `git commit -m "first commit"
  3. Add your remote to your local repo: git remote add origin https://github.com/dfkaye/dfkaye-blog.git
  4. Push your changes up: git push -u origin master
  5. Verify the push made it to the repo on github.com.
  6. Verify the build on the host provider.

If the build fails on the host provider...

That's good news. The host is running the build command (hugo) and finding problems. Now you can trouble-shoot.

In my case, the content path was not resolved because we didn't add anything to the content folder yet.

Add a something to /content

Create a markdown file like first.md with content like so:

title: "First"
date: 2019-11-11T12:44:58-08:00
draft: false
summary: 'first page'
# script: 'first.js'
---

# first

first blog post in hugo with javascript files eventually.

Then git add ., git commit -m "add content for netlify build to work", git push -u origin master`.

Visit the host deployment panel to verify the build, which should resolve this time.

Add a stylesheet

Create a static/css folder.

Then create a main.css file with p { color: aqua; } or something equally unmistakable and put it in the static folder.

Add this to layouts/index.html:

	{{ $css := "css/main.css" | absURL }}
	<link rel="stylesheet" href="{{ $css }}">

Localhost should reload with an aqua paragraph for "Home".

If Hugo throws an error about resolving the content path...

Stop and restart the hugo server.

Creating the folder with the hugo server is running can throw it out of sync with the file system.

Add a JavaScript file

Create a static/js folder.

Then create a hello.js file with console.log("hello"); and put it in the static/js folder.

Add this to layouts/index.html:

	{{ $js := "js/hello.js" | absURL }}
	<script src="{{ $js }}"></script>

Open the console and verify that "hello" appears.

Viewing Hugo localhost on your mobile device

Find your system's IP address, then use the bind and baseURL flags with hugo server.

Example: $ hugo server --bind=192.168.0.108 --baseURL=http://192.168.0.108:1313

Open http://192.168.0.108:1313 on your device.

From here...

Now that you have verified the publish process works and you can test local changes on multiple devices, you can delete things and get started for real.

Follow the steps in Zach Betz's post, "Make a Hugo blog from scratch". Zach has several other posts on doing things in hugo.

If you'd rather follow a book, I recommend Brian Hogan's, Build Websites with Hugo, obtainable from bookshop.org.

Some blog layouts worth considering

See also

Visit Chris Ferdinandi's hugo starter kit for other ideas.

Visit my github repo (if you want to).

Problem with wordpress and gatsby

"importing" page-scoped javascript files not easily supported (wordpress: paid plan, gatsby: react scrubs them from markdown).

HOW TO DO IT IN HUGO

Assume you we have a static/js/page-specific.js file.

Using partials

Create a layouts/_default/baseof.html file similar to this:

<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
    <head>
	<title>{{ block "title" . }}{{ .Site.Title }}{{ end }}</title>
	{{- partial "head.html" . -}}
    </head>
    <body>
	{{- partial "header.html" . -}}
	<main id="main">
	    {{- block "main" . }}{{- end }}
	</main>
	{{- partial "social.html" . -}}
	{{- partial "footer.html" . -}}
	{{- partial "js.html" . -}}
	{{- template "_internal/google_analytics.html" . -}}
    </body>
</html>

To use the {{- partial "js.html" . -}} template, create a layouts/partials/js.html file that reads from .Params.script

	{{ $pageScript := .Params.script }}
	{{ if $pageScript }}
	<script src="{{ .Site.BaseURL }}js/{{ $pageScript }}"></script>
	{{ end }}

The path {{ .Site.BaseURL }}js/{{ $pageScript }} will resolve to static/js/...

In the front-matter of your page markdown, add a script entry with a single string naming the file:

	---
	script: 'page-specific.js'
	---

For multiple scripts, you can use a range:

	{{ range .Site.Params.scripts }}
	<script src="{{ $.Site.BaseURL }}js/{{ . }}"></script>
	{{ end }}

Then specify scripts as an array of entries in the markdown front-matter:

	---
	scripts: ['page-specific.js', 'another-one.js']
	---

Script tag in markdown

If you have static/js/page-specific.js, in the page markdown you can include a script with a relative path to js/page-specific.js. Or even multiple scripts:

	<script src="js/first.js"></script>
	<script src="js/second.js"></script>

That will work as a one-off, but putting things in the layout partials means you're always loading external scripts into the same point within the output HTML.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment