User Tools

Site Tools


hugo

Setting up a minimal Hugo website

I discovered a most excellent thing recently for developing websites: Hugo. More truthfully, a friend got me onto it. At first I couldn't see the point of something that generates static pages from source.

Why not just use PHP or .NET or some other server side solution? As it turns out, there is something pretty elegant about being able to serve out standard HTML from any server and not have to bother about setting up services on a host.

As cool as it is, it's not straight forward to get a minimal set up going. You can follow the Hugo Quick Start Guide, but the guide centres around using a specific full featured theme (it will fail without it) and the guide doesn't cover standard inclusions like CSS or Javascript.

You end up asking more questions with the Hugo Quick Start Guide than you get answered.

This guide shows you how to set up a bare bones Hugo-based website and how to include commonly needed features. I believe this is how most users will want to start out.

Downloading Hugo

One of the coolest things about Hugo is that everything is managed using a single Hugo executable. There is no NodeJS/npm, Ruby or bloatware in sight!

Download the Hugo executable for your operating system here: https://github.com/gohugoio/hugo/releases

Unzip or unpack and (in the case of Windows) get the hugo.exe. For Linux or Mac, the file will be hugo. For the rest of the tutorial, I'll assume you're using Windows.

Creating the website

Copy the hugo.exe file to some folder where you want to create a site. In this example, I'll copy hugo.exe to my C:\Work folder.

Open a command windows and CD your way to C:\Work.

Our website will be about echidnas, so create the site with:

hugo new site echidna-fans

A bunch of folders and some files will be created:

│
├───archetypes
│       default.md
│
├───content
├───data
├───layouts
├───static
└───themes
config.toml

Archetypes folder: won't be covering this. Ignore it for now.

Content: this is the folder that will hold the actual written page content. The content here will be used to turn into web pages. The file format will be Markdown, which is a pleasant format to work in. Much cleaner than HTML.

Data: this folder opens many possibilities for managing lists of content. We'll cover this later.

Layouts: Not used in this tutorial. Ignore it. However we will use a “Layouts” folder in a theme later on.

Static: Not used. However we will use a “Static” folder in a theme later on to store any CSS, Javascript files, or images.

Themes: we definitely will need a minimal theme to operate with. This is where this tutorial greatly differs from the Quick Start Guide. We'll make our own from scratch. Without a theme Hugo will generate a blank site, but will give no errors to guide what specifically is wrong.

Config.toml: this file is where we set important information about the site, for example: the URL where this site will reside, and what theme it uses, etc.

Moving the Hugo executable

This might seem an odd thing, but locate the Hugo executable that is currently in the C:\Work folder and move it to the C:\Work\echidna-fans folder. Why? Because we will now use the Hugo executable within our website folder to create a theme and do other handy things.

Of course, we could copy the Hugo executable to a place on our drive with other executables and set it's path to the PATH environment variable. But for some people, this is too technical to bother with. And it's likely you may only be intending to ever work on one Hugo site. So keep the executable with your site, and keep things easy.

Creating a basic theme

The Quick Start Guide recommends downloading a theme to use with a new site but it's rather full featured and does little to guide someone to building up their own.

Therefore, create a blank theme from within the echidna-fans folder with:

hugo new theme echidna-theme

The following folders will be created under the C:\Work\echidna-fans\themes folder:

└───echidna-theme
    │   LICENSE
    │   theme.toml
    │
    ├───archetypes
    │       default.md
    │
    ├───layouts
    │   │   404.html
    │   │   index.html
    │   │
    │   ├───partials
    │   │       footer.html
    │   │       head.html
    │   │       header.html
    │   │
    │   └───_default
    │           baseof.html
    │           list.html
    │           single.html
    │
    └───static
        ├───css
        └───js

theme.toml: used to declare meta data about the theme, the author, license etc.

Archetypes: not used in this tutorial.

Layouts: very important. Contains the layout and look of your index page, other pages, lists, 404 pages. Both complete and partial pages are stored here like headers and footers. We'll make extensive of these. At the moment, these pages are blank and so our site is not yet ready to try.

Static: used to store your CSS, Javascript and images for your site.

Finally, your site needs to select this new theme. Edit the C:\Work\config.toml file and add a theme line at the end:

baseURL = "http://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "echidna-theme"

Creating the default Index page

Every site has an index.html page. We'll create this now. Type:

hugo new content/_index.md

This creates the _index.md markdown page inside the content folder. It has to be called by this special file name.

If you edit the file you'll see:

---
title: "Content"
date: 2019-11-16T21:54:07+11:00
draft: true
---

There's not much in there at the moment, just the title, and if it's in draft mode. I'll explain this mode later, but now just know that draft pages won't be rendered when we build a static site.

Let's add a header and a sentence for the page using standard markdown syntax:

# All About Echidnas

Echidnas are a fascinating Australian animal. This site is for all echidna fans.

Now that we have built the content for our default index page, we don't have enough to test yet. This because we do not yet have a layout for an index page. Find the layout file at: echidna-fans/themes/layouts/index.html and edit.

The file will be blank, so we need to provide some very simple HTML which will be wrapped around our content markdown file:

<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body>
	{{ .Content }}
</body>
</html>

Notice the {{ .Content }} tag? This is how Hugo knows to get the _index.md content and insert it into the body here.

First Test

You can now start serving your site locally and test in a browser with:

hugo server -D 

Fire up a browser and go to http://127.0.0.1:1313

Your page will appear:

All About Echidnas

Echidnas are a fascinating Australian animal. This site is for all echidna fans.

It's not flash, but it's a start.

While the “Hugo server” is running, if you create or change any files, your site will automatically reload for you. No need to stop and start the Hugo server.

CSS and Javascript

Two very common and useful things to add to a site. We'll start with a basic CSS file. Create a file called styles.css and place it into the echidna-fans/themes/echidna-theme/static/css/ folder.

Edit it just to have a couple of styles:

body {
	font-family: verdana;
	font-size: 16px;
}

h1 {
	font-size: 20px;
	color: #0088FF;
}

Then include this file into the index.html layout file:

<!DOCTYPE html>
<html>
<head>
	<link rel="stylesheet" href="../../css/styles.css">
	<title>Test</title>
</head>
...

The page styles should instantly change in your browser and you will get a nice new blue heading.

You can include Javascript just the same way that you would be used to. Create the following echidnas.js file in the echidna-fans/themes/echidna-theme/static/js/folder:

console.log('Javascript works!');

Then add it to your index.html file:

...
<body>
	{{ .Content }}
</body>
<script type="text/javascript" src="../../js/echidnas.js"></script>
</html>

Check the developer console in your browser to confirm the Javascript is working.

Breaking up the layouts

This is one of Hugo's main features: the ability to break up a layout into small reusable pieces, or “partials”. For example, in our index.html file, it would be good to break it up into a common header and a common footer so that it could be used for, say, the single.html layout.

What is the single.html layout you ask? It's the layout used for any other content file other than the _index.md one.

Therefore is makes sense to use a common header and footer for both the index.html and single.html templates if this suits your site design.

head.html, header.html and footer.html layout partials are provided for us by Hugo (blank of course). Let's make use of some of those.

First, move the top part of index.html into the head.html layout file:

<!DOCTYPE html>
<html>
<head>
	<link rel="stylesheet" href="../../css/styles.css">
	<title>Test</title>
</head>
<body>

Move the following ending to the footer.html layout file:

</body>
<script type="text/javascript" src="../../js/echidnas.js"></script>
</html>

Now for the trick. Change index.html to simply contain:

{{ partial "head.html" }}
	{{ .Content }}
{{ partial "footer.html" }}

Excellent. The site should look no different.

So what about a new page? Copy the contents of index.html to the single.html file so that they operate the same way.

Stop the server with Control-C so that we can create a contact file where people can find out how to contact us:

$ ./hugo.exe new contact
C:\Work\echidna-fans\content\contact created

You can put the server back on now.

Edit the contact.md file and add the following in:

# Contact Us

A contact us page.

Visit the name page link at: http://127.0.0.1:1313/contact

Nice. So the contact.md will use the single.html layout to display its page.

Contact Us

A contact us page.

Data Templates

A cool thing that Hugo can do is produce lists of data using Data Templates. There are many ways to provide data to Hugo, a local JSON, YAML or TOML file, or retrieving a file from the web.

In this example, we'll create our own JSON data file, and use this to produce a list in a partial. And this partial will be placed in the index file.

Create a data file, called: echidnas.json in the echidna-fans/data folder:

{
	list: [
		{
			"name": "Short-beaked Echidna"
			"country": "Australia"
		},
		{
			"name": "Long-beaked Echidna"
			"country": "New Guinea"
		}
	]
}

Next is the create a partial that will use this data to make a list from. Create an echidna-list.html file in the echidna-fans/themes/echidna-theme/layouts/partials folder.

<div>
	<ul>
		{{ range .Site.Data.echidnas.list }}
		<li>{{ .name }}</li>
		{{ end }}
	</ul>
</div>

So what's going on in this file here? By using .Site.Data.echidnas.list, we are saying: get the Data folder from our site (which is echidna-fans/data), get the echidna.json file (we don't have to specify the .json extension), and finally get the list collection inside the file.

Then “range” over it, or “work through” each item in the array.

Finally, place the name property into our page. Very very neat. This allows someone else to work on the data to display in your site while you work on the layout implementation.

Next, tell index.html about the new echidna-list.html partial:

{{ partial "head.html" }}
	{{ .Content }}
	{{ partial "echidna-list.html" . }}
{{ partial "footer.html" }}

If we place the partial into the index.html file, we are effectively placing a component into the page

Warning: Please note the “.” in {{ partial "echidna-list.html" . }}. This is important. Without passing the current scope “.” in, echidna-list has no knowledge of the data or variables. You'll get nothing. Nor will you get an error message. Ensure the dot (.) or troubleshooting will be very difficult.

Note: Hugo is very fussy with the JSON formatting and thankfully if you make a mistake in your JSON file, Hugo will warn you.

Note: If you correct a mistake in your JSON file, sometimes Hugo doesn't quite get it, and might still complain about the same error even though it's fixed. In these cases, try stopping and starting the Hugo server.

Publishing your site

Here comes the last step of using Hugo. You can stop using the Hugo server and have it generate your final static files to upload to your web host online.

The first step is to go to each file in your content folder and change:

draft: true

to

draft: false

The draft property has no effect with the Hugo server when testing a page. But the page will be ignored when generating the static files. Very handy for working on pages in various states of readiness when working in a team.

Next is to set the baseURL of your site that you will upload to. This will assist the Hugo static generator to get the paths correct on your images, CSS, JSON and other files. Find baseURL in the echidna-fans/config.toml file.

baseURL = "http://example.org/"
...

So you can set it to the site you want to publish to for example:

baseURL = "http://echidna-fans.org.au/"
...

And if you generated, then uploaded all your files to that webspace, in the perfect world all would be fine and dandy. But Hugo has a problem here.

Rarely would you want to upload your in-progress site to the actual destination. It would ruin the surprise right? Or you might be replacing an old site, and you don't want to mess up the files in place.

A common use case would be to create a separate subfolder to hold the site in development like:

http://echidna-fans.org.au/new-site

Setting…

baseURL = "http://echidna-fans.org.au/"

…will work just fine. But this will mess up your local developer server. Hugo simply doesn't like subfolders added to the end of the baseURL. It will report all kinds of weird errors.

The Hugo documentation states that `baseURL = “http://example.org/“` is ignored. However if you were to add a subfolder to that address, you would mess up Hugo.

The workaround is to have two entries that you can swap around prior to generating:

baseURL = "http://example.org/"
_baseURL = "http://echidna-fans.org.au/new-site"

If you do mess up Hugo in this way, when you correct it, you need to stop and start the Hugo server.

Conclusion

That should give you a good solid start, covering the most common requirement in a basic site: styles and other static content, headers, footers, and content generated from contributed data.

For the more experienced Hugo users out there, it is very likely there are answers for the problems outlined in this article. If you know simple solutions, do please let me know. The Hugo documentation only gives so many examples (they are usually from a more narrow point of view), and from pouring over many forum posts, many issues appear to be not resolved.

That said, Hugo is a great tool and gives you the ability to build your site dynamically during development, but serve it out as static. That gives you the power to run your site on the most simple of hosts, or even from your own home server.

hugo.txt · Last modified: 2020/10/02 20:27 (external edit)