Hugo (Go)
Links
A static-site generator written in Golang.
Resources
Installing
1
| Hugo Static Site Generator v0.80.0/extended darwin/amd64 BuildDate: unknown
|
Creating a new site
1
| hugo new site <folder-name>
|
Structure
1
2
3
4
5
6
7
8
9
| ls -1
archetypes/
config.toml
content/
data/
layouts/
static/
themes/
|
- archetypes/ - entities that are smth like markdown templates of content
- config.toml - main configuration file
- content/ - folder that contains markdown content
- data/ - folder that contains configuration files and data that used in generating your site
- layout/ - folder that contains html templates for specific parts of website
- static/ - folder that contains static files like images, fonts, etc.
- themes/ - folder that can contain existing Hugo themes
Starting website
To running and see draft content:
The empty white page in just created app is okay
On root route (/) Hugo try to render layout with name:
- list.html
- or
- index.html (index.html takes priority)
Types of pages:
- single (page of the specific post)
- list (page that contains list of posts)
Configuration file
By default it is config.toml
It is possible to use YAML file. Just rename it to config.yml
Default settings:
config.toml
1
2
3
| baseURL = "http://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
|
config.yml
1
2
3
| baseURL: "http://example.org/"
languageCode: "en-us"
title: "My New Hugo Site"
|
Templating
Create template of the main page in path /layouts/list.html
Add website title
1
2
3
4
5
6
7
8
9
10
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Site.Title }}</title>
</head>
<body></body>
</html>
|
.Site.Title:
- Site - context
- it is context of config.yml file
- Title - variable
Add page title
Create file /content/_index.md
1
2
3
| ---
title: "Home"
---
|
- _index.md - file that contains content of home page (root route - ‘/’)
Add title of home page in /layouts/list.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Site.Title }}</title>
<!-- Title of website -->
</head>
<body>
<h1>{{ .Page.Title }}</h1>
<!-- Title of the page -->
</body>
</html>
|
Because the layout is already in context of the page you can just change it:
1
2
| <h1>{{ .Page.Title }}</h1>
<!-- Title of the page -->
|
to
1
2
| <h1>{{ .Title }}</h1>
<!-- Title of the page -->
|
Render list of pages in loop
Create new pages /content/about.md and /content/contact.md
1
2
3
| ---
title: "About"
---
|
To render list of these pages with their links just add this code in layouts/list.html:
1
2
3
4
5
| <ul>
{{ range .Pages }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
</ul>
|
- range is a loop here. it iterates in .Pages which is a list of data about each page
- .Permalink - link to the specific page
- .Title - the title of the page which is declared in markdown metadata
Default layouts
Create folder /layouts/_default and move layouts/list.html there
Layouts from this folder /layouts/_default will be used for all content by default
Creating template for a single page
Create file /layouts/_default/single.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Title }} | {{ .Site.Title }}</title>
</head>
<body>
<h1>{{ .Title }}</h1>
<div>{{ .Content }}</div>
</body>
</html>
|
If you open page /about in the browser you’ll see this html structure.
Display list of pages with specific type
Change the loop in the layout to display list of resources that have type “page”:
1
2
3
4
5
| <ul>
{{ range where .Pages "Type" "page" }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
</ul>
|
By default markdown resources in /content has type “page”.
If you don’t want to show some specific resource as page you can specify type in metadata:
1
2
3
4
| ---
title: "About"
type: "post"
---
|
Display list of pages/posts of specific section
What is Section?
More information you can find in official doc of Hugo
I understand sections like sub folders in a folder content
Basically, you have a folder content that contains two folders - blog and notes.
In that case, blog and notes are Sections in Hugo.
Display list of resources of section “blog”
1
2
3
4
5
| {{ range where .Site.RegularPages "Section" "blog" }}
<li>
<a href="{{ .Permalink }}">{{ .Title }}</a>
</li>
{{ end }}
|
1
2
3
4
5
6
7
8
9
10
| <div>
{{ $paginator := .Paginate (where .Pages "Section" "blog") }} {{ range
$paginator.Pages }}
<article>
<div>
<a href="{{ .Permalink }}">{{ .Title }}</a>
</div>
</article>
{{ end }} {{ template "_internal/pagination.html" . }}
</div>
|
Splitting layouts
Let’s say we have two layouts: for home page layouts/_default/list.html and for single page layouts/_default/single.html
They have pretty similar html structure:
list.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Site.Title }}</title>
<!-- Title of website -->
</head>
<body>
<h1>{{ .Title }}</h1>
<div>
<ul>
{{ range where .Pages "Type" "page" }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
</ul>
</div>
</body>
</html>
|
single.html
1
2
3
4
5
6
7
8
9
10
11
12
13
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Title }} | {{ .Site.Title }}</title>
</head>
<body>
<h1>{{ .Title }}</h1>
<div>{{ .Content }}</div>
</body>
</html>
|
To avoid repeating code we can make base layout that will contain common html structure.
Create the file /layouts/_default/baseof.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Site.Title }}</title>
<!-- Title of website -->
</head>
<body>
<h1>{{ .Site.Title }}</h1>
<div>
<ul>
{{ range where .Site.RegularPages "Type" "page" }}
<li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
</ul>
</div>
{{ block "content" . }}{{ end }}
</body>
</html>
|
{{ block "content" . }}{{ end }}
renders layouts that have the same “name”
For home page let’s change /layouts/_default/list.html:
1
2
3
| {{ define "content" }}
<h2>Index</h2>
{{ end }}
|
And now the baseof layout renders the sub layout list.html for home page
For single page let’s change /layouts/_default/single.html:
1
2
3
4
| {{ define "content"}}
<h2>{{ .Title }}</h2>
<div>{{ .Content }}</div>
{{ end }}
|
Creating blog section
Create folder /content/blog and put there new file /content/blog/_index.md
1
2
3
| ---
title: "Blog"
---
|
And then create a few blank posts:
1
2
3
4
5
| ---
title: "First Post"
---
Deserunt duis fugiat reprehenderit officia cillum qui cillum Lorem. Aliquip sint esse fugiat elit. In incididunt quis ullamco cupidatat tempor. Lorem ad non incididunt ad magna nostrud.
|
1
2
3
4
5
| ---
title: "Second Post"
---
...
|
Layout of posts list
To display list of posts let’s create new layout. But first of all, we need to create new folder /layouts/blog.
Why?
- /layouts/_default could used for general resources like pages
- /layouts/blog here are layouts for resources like blog posts
In /layouts/blog create file list.html:
1
2
3
4
5
6
7
8
9
10
11
12
| {{ define "content" }}
<div>
<h2>{{ .Title }}</h2>
<ul>
{{ range where .Site.RegularPages "Type" "blog" }}
<li>
<a href="{{ .Permalink }}">{{ .Title }}</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
|
It will display list of posts links
Layout of specific post
Let’s create a layout for page of post
In folder /layouts/blog create file single.html:
1
2
3
4
5
6
| {{ define "content" }}
<div>
<h2>Post: {{ .Title }}</h2>
<div>{{ .Content }}</div>
</div>
{{ end }}
|
This html structure will be used only for posts. It won’t be used for all pages (for example about or contact).
Using partials templates
Partials templates are specific layouts or files that can be used as parts of layout.
Let’s say we have file /layouts/_default/baseof.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Site.Title }}</title>
<!-- Title of website -->
</head>
<body>
<!-- something here -->
</body>
</html>
|
Here we have section head that we could make it as partial template.
Create folder /layouts/partials. It is a specific folder for all partials.
In that new folder let’s create file head.html with head section of html structure:
1
2
3
4
5
6
7
| <head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Site.Title }}</title>
<!-- Title of website -->
</head>
|
To use this partial change the file baseof.html:
1
2
3
4
5
6
7
8
9
| <!DOCTYPE html>
<html lang="en">
<!-- using partial with section "head" -->
{{ partial "head" . }}
<body>
<!-- something here -->
</body>
</html>
|
Shortcodes
What Are Shortcodes?
More information here (gohugo.io)
Basically, it’s something similar to components in MDX but without React/JSX.
You can put a specific code in your markdown file and it will be rendered like a widget.
Built-in Shortcodes
There are several built-in shortcodes in Hugo that can be used out of box.
For example, shortcode youtube that renders a video on the page:
Taxonomies
Basically, taxonomies are tags and categories or some new thing that (you can make it) has similar behavior to tags or categories.
I take it that way:
- Sections: One-to-many
- one section (blog)
- many resources
- Taxonomies: Many-to-many
- many taxonomies (tags)
- many resources
Creating a new taxonomy
Let’s call it technologies
First of all, we need to specify new taxonomy in config file:
1
2
3
4
5
6
7
| baseURL: "http://example.org/"
languageCode: "en-us"
title: "My New Hugo Site"
taxonomies:
category: categories
tag: tags
technology: technologies
|
notice that we need to specify built-in taxonomies too if you want to use them
Add this in some of your markdown resources:
1
2
3
4
5
6
| ---
title: "Second Post"
technologies: ["typescript", "react", "node"]
---
...
|
To render the list of technologies in each post:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <div>
{{ $paginator := .Paginate (where .Pages "Section" "blog") }} {{ range
$paginator.Pages }}
<article>
<!-- ... -->
<div>
{{ range (.GetTerms "technologies") }}
<li><a href="{{ .Permalink }}">#{{ .LinkTitle }}</a></li>
{{ end }}
</div>
<!-- ... -->
</article>
{{ end }} {{ template "_internal/pagination.html" . }}
</div>
|
To render the list of posts that has specific technology:
- file: /layouts/taxonomy/technology.html
- in the browser: /technologies/typescript
1
2
3
4
5
6
7
8
9
10
11
12
| {{ define "content" }}
<div>
<h2>Technology: {{ .Title }}</h2>
<ul>
{{ range .Data.Pages }}
<li>
<a href="{{.RelPermalink}}">{{ .Title }}</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
|
Tags in Hugo are built-in taxonomies.
Adding tags into the post
1
2
3
4
5
6
7
8
9
10
11
| <!-- /content/blog/First Post.md -->
---
title: "First Post"
draft: false
tags: ["tag1", "tag2"]
---
....
|
Creating a page with all tags of all resources (posts)
- file: /layouts/tag/list.html
- in the browser: /tags
1
2
3
4
5
6
7
8
9
10
| {{ define "content" }}
<div>
<h2>{{ .Title }}</h2>
<ul>
{{ range .Site.Taxonomies.tags }}
<li><a href="{{ .Page.Permalink }}">{{ .Page.Title }}</a> {{ .Count }}</li>
{{ end }}
</ul>
</div>
{{ end }}
|
Creating a page of specific tag with list of posts
- file: /layouts/taxonomy/tag.html
- in the browser: /tags/<tag_name>
1
2
3
4
5
6
7
8
9
10
11
12
| {{ define "content" }}
<div>
<h2>#{{ .Title }}</h2>
<ul>
{{ range .Data.Pages }}
<li>
<a href="{{.RelPermalink}}">{{ .Title }}</a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
|
Useful links