Hugo 官方文档
This is the multi-page printable view of this section. Click here to print.
Hugo 常用记录
- 1: 命令行(Command)
- 2: 目录结构(Directory-structure)🔥
- 3: 标记解析(Markup)
- 4: 布局使用(Layout-usage)🔥
- 5: 布局定制(Layout-custom)📦
- 6: 内容管理(Content-Management)🔥
- 6.1: 前置元数据(Frontmatter)
- 6.2: 简码(Shortcode)
- 6.3: 分类法(Taxonomy)
- 7: 多语言支持(Multi-language)
1 - 命令行(Command)
命令行顾名思义,这里不赘述其具体用法 (具体用法参考hugo -h
或官方文档);这里仅做分类,作用快速查找。
帮助
环境
构建 🔥
测试 🔥
1hugo serve --buildDrafts --buildExpired --buildFuture
模块
转换/迁移
发布 🔥
2 - 目录结构(Directory-structure)🔥
官方文档: https://gohugo.io/getting-started/directory-structure/
项目目录结构:
example/
├── archetypes/
│ └── default.md
├── assets/
├── content/
├── data/
├── layouts/
├── public/
├── static/
├── themes/
└── config.toml
config.toml —— 存放配置
官方文档:
配置可以统一记录在一个文件中:
1contentDir = "content/en"
2defaultContentLanguage = "en"
3defaultContentLanguageInSubdir = false
4[[menu.main]]
5 name = "GitHub"
6 weight = 50
7 url = "https://github.com/google/docsy/"
8 pre = "<i class="fa-brands fa-github"></i>"
9 post = "<span class='alert'>New!</span>"
10[languages]
11[languages.en]
12title = "Docsy"
13description = "Docsy does docs"
14languageName ="English"
15# Weight used for sorting.
16weight = 1
17[languages.no]
18title = "Docsy"
19description = "Docsy er operativsystem for skyen"
20languageName ="Norsk"
21contentDir = "content/no"
22time_format_default = "02.01.2006"
23time_format_blog = "02.01.2006"
1contentDir: content/en
2defaultContentLanguage: en
3defaultContentLanguageInSubdir: false
4menu:
5 main:
6 - name: GitHub
7 weight: 50
8 url: 'https://github.com/google/docsy/'
9 pre: <i class="fa-brands fa-github"></i>
10 post: <span class='alert'>New!</span>
11languages:
12 en:
13 title: Docsy
14 description: Docsy does docs
15 languageName: English
16 weight: 1 # used for sorting
17 'no':
18 title: Docsy
19 description: Docsy er operativsystem for skyen
20 languageName: Norsk
21 contentDir: content/no
22 time_format_default: 02.01.2006
23 time_format_blog: 02.01.2006
1{
2 "contentDir": "content/en",
3 "defaultContentLanguage": "en",
4 "defaultContentLanguageInSubdir": false,
5 "menu": {
6 "main": [
7 {
8 "name": "GitHub",
9 "weight": 50,
10 "url": "https://github.com/google/docsy/",
11 "pre": "<i class="fa-brands fa-github"></i>",
12 "post": "<span class='alert'>New!</span>"
13 }
14 ]
15 },
16 "languages": {
17 "en": {
18 "title": "Docsy",
19 "description": "Docsy does docs",
20 "languageName": "English",
21 "weight": 1
22 },
23 "no": {
24 "title": "Docsy",
25 "description": "Docsy er operativsystem for skyen",
26 "languageName": "Norsk",
27 "contentDir": "content/no",
28 "time_format_default": "02.01.2006",
29 "time_format_blog": "02.01.2006"
30 }
31 }
32}
新版配置文件名使用
hugo.yaml
/hugo.toml
/hugo.json
。当然,向上兼容。
为了便于管理,也可以将其拆分为多个文件。
另一个好处是可以配置多个场景(profile)以应对不同情况的配置需求,比如production
是发布时使用的配置,staging
是本地预览时使用的配置。
1├── config
2│ ├── _default
3│ │ ├── config.toml
4│ │ ├── languages.toml
5│ │ ├── menus.en.toml
6│ │ ├── menus.zh.toml
7│ │ └── params.toml
8│ ├── production
9│ │ ├── config.toml
10│ │ └── params.toml
11│ └── staging
12│ ├── config.toml
13│ └── params.toml
archetypes —— 文章原型
通过 hugo new <文件名>.md
命令生成的 .md
文章会自动填充 archetypes/default.md
模板定义的内容。
assets —— 待加工资源
这里的文件可以被 Hugo Pipes 调用并处理,然后发布到 public/
目录。
官方文档:
- “Hugo Pipes” https://gohugo.io/hugo-pipes/
static —— 静态资源
存放静态文件,比如图片、CSS、JS
区别
assets/
和static/
目录:
assets/
—— 经过 Hugo Pipes 加工后才移动static/
—— 原封不动的移动到public/
目录
layouts —— 页面布局
转跳: 页面布局
themes —— 主题
一般将主题放进去后就不用管了。
Tips: 遇到问题可以直接看主题下的源码,有时比翻文档直接、快捷。前提需要对 Hugo 机制熟悉。
├── layouts
└── themes
└── mytheme
└── layouts
├── 404.html // 404页面模板
├── _default
│ ├── baseof.html // 默认的基础模板页, 使用的方式是'拼接', 而不是'继承'.
│ ├── list.html // 列表模板
│ └── single.html // 单页模板
├── index.html // 首页模板
└── partials // 局部模板, 通过partial引入
├── footer.html
├── header.html
└── head.html
content —— 内容管理
转跳: 内容管理
data —— 站点数据
官方文档:
- “Data templates” https://gohugo.io/templates/data-templates/
这里定义的数据可以在 config.yaml
中使用或者在 layouts/
中通过 $.Site.Data
获取。
e.g.
1discography = ['1974 - Modern American Music … Period! The Criteria Sessions', '1974 - Jaco', '1976 - Jaco Pastorius', '1981 - Word of Mouth', '1981 - The Birthday Concert (released in 1995)', '1982 - Twins I & II (released in 1999)', '1983 - Invitation', '1986 - Broadway Blues (released in 1998)', '1986 - Honestly Solo Live (released in 1990)', '1986 - Live In Italy (released in 1991)', "1986 - Heavy'n Jazz (released in 1992)", '1991 - Live In New York City, Volumes 1-7.', '1999 - Rare Collection (compilation)', '2003 - Punk Jazz: The Jaco Pastorius Anthology (compilation)', '2007 - The Essential Jaco Pastorius (compilation)']
1discography:
2- 1974 - Modern American Music … Period! The Criteria Sessions
3- 1974 - Jaco
4- 1976 - Jaco Pastorius
5- 1981 - Word of Mouth
6- 1981 - The Birthday Concert (released in 1995)
7- 1982 - Twins I & II (released in 1999)
8- 1983 - Invitation
9- 1986 - Broadway Blues (released in 1998)
10- 1986 - Honestly Solo Live (released in 1990)
11- 1986 - Live In Italy (released in 1991)
12- 1986 - Heavy'n Jazz (released in 1992)
13- 1991 - Live In New York City, Volumes 1-7.
14- 1999 - Rare Collection (compilation)
15- '2003 - Punk Jazz: The Jaco Pastorius Anthology (compilation)'
16- 2007 - The Essential Jaco Pastorius (compilation)
1{
2 "discography": [
3 "1974 - Modern American Music … Period! The Criteria Sessions",
4 "1974 - Jaco",
5 "1976 - Jaco Pastorius",
6 "1981 - Word of Mouth",
7 "1981 - The Birthday Concert (released in 1995)",
8 "1982 - Twins I \u0026 II (released in 1999)",
9 "1983 - Invitation",
10 "1986 - Broadway Blues (released in 1998)",
11 "1986 - Honestly Solo Live (released in 1990)",
12 "1986 - Live In Italy (released in 1991)",
13 "1986 - Heavy'n Jazz (released in 1992)",
14 "1991 - Live In New York City, Volumes 1-7.",
15 "1999 - Rare Collection (compilation)",
16 "2003 - Punk Jazz: The Jaco Pastorius Anthology (compilation)",
17 "2007 - The Essential Jaco Pastorius (compilation)"
18 ]
19}
layouts/home.html
1<ul>
2 {{ range $.Site.Data.jazz.bass.jacopastorius.discography }}
3 <li>{{ . }}</li>
4 {{ end }}
5</ul>
public —— 发布目录
用于存放生成的站点文件
1public/
2├── categories/
3│ ├── index.html
4│ └── index.xml <-- RSS feed for this section
5├── post/
6│ ├── my-first-post/
7│ │ └── index.html
8│ ├── index.html
9│ └── index.xml <-- RSS feed for this section
10├── tags/
11│ ├── index.html
12│ └── index.xml <-- RSS feed for this section
13├── index.html
14├── index.xml <-- RSS feed for the site
15└── sitemap.xml
3 - 标记解析(Markup)
官方文档: https://gohugo.io/getting-started/configuration-markup/ (配置看这里)
所谓 “标记解析” 就是将 .md
文件中的各种特殊字符、特殊格式转换为 .html
文件形式。可以理解为渲染 .md
文件。
Goldmark —— 解析 markdown 标记
Hugo 默认使用 goldmark 解析 markdown 标记。
下面记录常用配置
unsafe
是否允许渲染 html 代码块。默认不渲染,替换为 <!--raw HTML omitted -->
代码块。
attribute
是否解析 {...}
额外语法。默认不解析,直接识别为普通文本。
extensions
https://github.com/yuin/goldmark/#extensions
Highlight —— 配置"代码高亮"风格
Hugo 使用 chroma 作为代码高亮解析器。
官方文档:
- https://gohugo.io/getting-started/configuration-markup/#highlight (配置)
- https://gohugo.io/content-management/syntax-highlighting/ (简码形式)
- https://gohugo.io/functions/transform/highlight/ (函数形式)
1# config/_default/markup.yml
2highlight:
3 anchorLineNos: false # 为每一行代码标注链接,如:"#hl-3-6"为第三个代码块中第六行
4 lineAnchors: "" # 链接前缀,默认"hl"
5 codeFences: true # 解析{...}扩展选项
6 guessSyntax: false # 猜测语法,关闭加速编译
7 hl_Lines: ""
8 hl_inline: false # 行高亮,一般不在这里设置,在codeFence中设置
9 lineNoStart: 1
10 lineNos: false # 行号
11 lineNumbersInTable: true # 可能有适配问题,旧版本关闭的
12 noClasses: true # 使用class标签,而不是内嵌的内联样式
13 noHl: false
14 style: monokai # 代码高亮主题,参考 https://xyproto.github.io/splash/docs/all.html
15 tabWidth: 4
Table of contents —— 右侧文章大纲配置
简称 “TOC”
4 - 布局使用(Layout-usage)🔥
概念 - 使用布局的好处
在一个站点中,同一类页面(Page
)他们的样式一般是一样的。通过将共同的样式代码抽离为一个布局文件(Layout
)可以大大避免重复编码,简化编写页面的工作量。同时,也可以统一管理同一种页面的页面布局,使统一站点风格变得可能。
进一步考虑,将页面编写和布局编写的工作分开,可以将责任分割,进一步提高站点的可管理性:
- 文章编写者专心写文章
- 样式编写者专心定制站点样式,进一步封装成主题(
Theme
),可以跨站点使用。
概念 - 页面(Page)和页面布局(Layout)的对应关系
一般情况,我们使用 Hugo 时,会直接使用现成的主题(Themes)。因为主题里面有现成的布局,这样我们就不需要关心如何定制布局,而只需要关注如何使用布局,然后专心内容的编写即可。
当然,知道如何定制布局也非常有用,这将在下一章"布局定制“讨论
了解如何使用布局,首先需要知道页面(Page)和页面布局(Layout)的对应关系。
下图展示了对应关系的几种可能:
- 多数情况下,对应关系由 “模板查找顺序(Template lookup order)” 决定。
- 少数情况下,对应关系在前置元数据(FrontMatter)中指定。
flowchart LR subgraph Page p00[content/_index.md] p0[content/blog/_index.md] p1[content/blog/helloworld.md] p2[content/blog/test.md] p4["content/news/20231028-happynewyear.md"] p6["content/other/xx.md with `layout=blog`"] end subgraph "Type + Kind" s00["home + page"] s1["blog + index"] s2["blog + page"] s3["news + page"] end subgraph "Layout" l00["layouts/home.html"] l0["layouts/_default/single.html"] l1["layouts/blog/list.html"] l2["layouts/blog/single.html"] l3["[error] Unfound "layouts/news/single.html""] end p00 --> s00 p0 --> s1 p1 & p2 --> s2 p4 --> s3 p6 --> s2 s00 --> l00 s1 --> l1 s2 --> l2 s3 --> l3 l3 --> l0
- Kind ——
home
/page
/section
- Tyoe ——
page
/section-name(e.g.docs
/blog
/community
)
按模板查找顺序查找页面布局
根据 “模板查找顺序(Template lookup order)” 找到页面和页面布局的对应关系: (细节使用参考官方文档,下面仅为个人"最佳实践”)
- Type —— 页面类型,找到模板所在目录。如:
content/blog/xx.md
的Type默认为blog
,于是找有没有定义layouts/blog/
,如果没有则找layouts/_default/
- Kind —— 页面种类,找到模板
- home —— 固定位置
content/_index.md
文件使用layouts/home.html
页面布局 - section —— 顶部文件夹文件名
_index.md
文件 (如content/blog/_index.md
) 使用layouts/blog/list.html
页面布局 - page —— 非顶部文件夹文件名
_index.md
文件 (如content/docsy/content-management/_index.md
) 或者非_index.md
文件 (如content/docsy/command.md
) 使用layouts/docs/single.html
页面布局
- home —— 固定位置
一般依据上述规则就可以找到页面布局存放的位置。如果位置上没有页面布局文件,则找最近的
baseof.html
文件。
在前置元数据(FrontMatter)中指定页面布局
在 type
或者 layout
中指定 section
,必要的时候用 kind
指定页面类型。
e.g. 下面的前置元数据将指定使用 layouts/blog/single.html
模板
相关视频教程
(从左往右看)
5 - 布局定制(Layout-custom)📦
官方文档:
- https://gohugo.io/templates/ (模板使用)
模板引擎
布局使用: 参考"布局使用"
Hugo 使用 Go 中 html/template 库 作为模板引擎。
通过模板引擎,可以解析模板中的 {{...}}
标签。
标签 {{...}}
在 Go 中称为 “Action” (动作)。
动作包括两种类型:数据求值和控制结构。
基础语法
1//点 2{{ . }} 3代表传递给模板的数据,表示当前模板的上下文,可以是 Go 语言中的任何类型,比如字符串、数组、结构体等 4点的使用参考:https://www.regisphilibert.com/blog/2018/02/hugo-the-scope-the-context-and-the-dot/ 5 6//注释 7{{/* comment */}} 8 9//空格 10{{- pipeline -}} // 清除 pipeline 前后的空格 11{{- pipeline }} // 清除 pipeline 前面的空格 12 13//变量赋值 14{{$变量名 := "值"}} 15 16//条件判断 17{{if pipeline}} T1 {{else}} T0 {{end}} 18如果不为空则输出T1,否则输出T0 19{{if pipeline}} T1 {{else if pipeline}} T0 {{end}} 20 21//循环语句 22{{range pipeline}} T1 {{end}} 23pipeline 的值必须是数组,切片,map,channel,设置 点. 为数组,切片遍历 map 的值,输出T1 24 25//with 重设点.的值 26{{with pipeline}} T1 {{else}} T0 {{end}} 27如果 pipeline 的值为空, 点. 的值不受影响,输出T1,否则 点. 的值设置成 pipeline 的值,输出T0
定义子模板
1//define 2{{define "name"}} T1 {{end}} 3定义一个特定名称的模板 4 5//template 6{{template "name"}} 7引入指定名称的模板,不传入任何数据. 8 9{{template "name" pipeline}} 10引入指定名称的模板,设置模板上下文 点. 的值为 pipeline 的值 11 12//block 13{{block "name" pipeline}} T1 {{end}} 14定义特定名称的模板,并在当前位置引入该名称的模板,模板的上下文 点. 的值为 pipline 的值,如果该名称的模板未实现(不存在),则输出T1
变量/函数/数据
官方文档:
- https://gohugo.io/variables/ (变量列表)
- https://gohugo.io/functions/ (函数列表)
本站示例: 测试模板中函数和变量的取值
视频教程:
逻辑
视频教程:
6 - 内容管理(Content-Management)🔥
content/<section_name>/**/<content_name>.md
文件。
(涉及东西多,篇幅长)content 的目录结构
└── content
├── _index.md // [home] <- https://example.com/ **
├── about.md // [page] <- https://example.com/about/
├── posts
| ├── _index.md // [section] <- https://example.com/posts/ **
| ├── firstpost.md // [page] <- https://example.com/posts/firstpost/
| ├── happy
| | ├── _index.md // [section] <- https://example.com/posts/happy/ **
| | └── ness.md // [page] <- https://example.com/posts/happy/ness/
| └── secondpost.md // [page] <- https://example.com/posts/secondpost/
└── quote
├── _index.md // [section] <- https://example.com/quote/ **
├── first.md // [page] <- https://example.com/quote/first/
└── second.md // [page] <- https://example.com/quote/second/
// hugo默认生成的页面, 没有对应的markdown文章
分类列表页面 // [taxonomyTerm] <- https://example.com/categories/ **
某个分类下的所有文章的列表 // [taxonomy] <- https://example.com/categories/one-category **
标签列表页面 // [taxonomyTerm] <- https://example.com/tags/ **
某个标签下的所有文章的列表 // [taxonomy] <- https://example.com/tags/one-tag **
中括号
[]
中标注的是页面的kind属性, 他们整体上分为两类: single(单页面 - page) 和 list(列表页 - home, section, taxonomyTerm, taxonomy).
6.1 - 前置元数据(Frontmatter)
官方文档:
使用
page
1# content/test/_index.md
2title: "My amazing new section"
3weight: 1
4type: docs
5description: >
6 A special section with a docs layout.
list/section
1# content/news/_index.md
2title: "Latest News"
3linkTitle: "News"
4menu:
5main:
6 weight: 30
7cascade:
8 - type: "blog"
1# content/sections01/_index.md
2
3# section 子文章"块"显示
4simple_list: true # 列表显示
5no_list: true # 不显示
链接 linking
ref
—— 绝对路径relref
—— 相对路径
1# hostname=localhost
2# port=1313
3# baseurl=/
4.
5└── content
6 ├── document1.md
7 ├── about
8 | ├── _index.md
9 | └── document1.md
10 ├── pages
11 | ├── current.md <----------- current
12 | ├── document1.md
13 | └── document2.md // has anchor #anchor
14 ├── products
15 | └── index.md
16 └── blog
17 └── my-post.md
18
19e.g.
20{{< relref "document1.md" >}} --> 可以忽略后缀
21{{< relref "document1" >}} --> 输出: /content/pages/document/
22{{< ref "document1" >}} --> 输出: //localhost:1313/content/pages/document/
23{{< ref "document2.md#anchor" >}}
24{{< ref "document1" >}} --> 找到: /content/pages/document1.md
25{{< ref "/document1" >}} --> 找到: /content/document1.md
26{{< ref "/about/document1" >}} --> 找到: /content/aboug/document1.md
路径不需要绝对"准确",hugo会(按照优先级)自动匹配最适合的结果。
优先级:
./*
./**
content/*
content/**
6.2 - 简码(Shortcode)
我们在文章内容 content/**.md
可以重复多处调用这种代码块来减少重复性操作。
区分: 简码(Shortcode)和模板变量与函数(Template variable and function)
模板的设计初衷是简化操作,避免重复编码。但是如果(表达作者思想的)文章中出现大量(页面渲染和逻辑判断相关的)模板语句会使文章管理变得混乱。
为了避免上述问题,Hugo 提出简码的概念: 文章作者不能直接在文章中使用模板语言,但是可以使用模板语言封装后的"简码(Shortcode)"。简码封装了模板语言涉及的html和逻辑判断。使用简码只需要传入必要参数即可。
- 模板变量调用:
{{ .Title }}
- 模板函数调用:
{{ dict "title" .Title content" "hello!" | jsonify }}
- 简码调用:
{{< highlight go >}} hello {{< /highlight >}}
总结: 模板只能在
layouts/
中使用;简码只能在content/
中使用。这样就划分了两个角色: 编写模板的主题作者和编写文章的内容作者!
官方文档:
- https://gohugo.io/content-management/shortcodes/#use-hugos-built-in-shortcodes (内置简码列表)
- https://gohugo.io/templates/shortcode-templates/ (自定义简码)
- https://gohugo.io/variables/shortcodes/ (自定义简码中可用变量)
调用
有两种调用形式:
{{< ... >}}
—— 不对传入参数进行处理{{% ... %}}
—— 对传入参数进行加工,如进行markdown标志的解析
有三种参数传递形式:
{{< shortcodename >}}
—— 不传参{{< shortcodename parameters >}}
—— 传入"string"
或者key="value"
形式的参数 (简码中会通过.Get
函数获取传入参数){{< shortcodename >}} inner string {{< /shortcodename >}}
—— 用两个简码标记包裹字符串 (简码中会通过.Inner
变量获取包裹的字符串)
简码"不解析"
有的时候,我们就希望简码字符直接以字符形式显示,像 “{{< string >}}
” 这样。这时我们只需要将内容用 /* ... */
包裹,如 “{{</* string */>}}
” 写在 .md
文件中。
6.3 - 分类法(Taxonomy)
默认有 tags
和 categories
两个。添加更多只需要在配置文件配置:
默认会把全部标签显示在右侧,称为 “标签云(taxonomyCloud)"。 可以配置只显示一部分标签:
1params:
2 taxonomy:
3 taxonomyCloud:
4 - projects # remove all entries
5 - tags # to hide taxonomy clouds
6 taxonomyCloudTitle: # if used, must have the same
7 - Our Projects # number of entries as taxonomyCloud
8 - Tag Cloud
9 taxonomyPageHeader:
10 - tags # remove all entries
11 - categories # to hide taxonomy clouds
7 - 多语言支持(Multi-language)
官方文档:
- https://gohugo.io/content-management/multilingual/ (multilingual)
页面框架"国际化"
首先,需要在 i18n/
目录中定义多语言的显示内容。 (这些内容一般由主题项目提供)
i18n/
├── en.toml (默认)
└── zh-cn.toml <---- 新增
然后,在配置文件中更改 defaultcontentlanguage 配置设置。 (默认en
)
1defaultcontentlanguage: zh-cn
最后,通过调用模板函数 {{ T "ui_pager_prev" }}
就能得到当前环境的框架文本。
文章内容"国际化"
https://www.docsy.dev/docs/language/
https://before80.github.io/docsy_docs_with_hugo/docs/Multi-languageSupport/
1content/en/
站点检索"国际化"
设置 languagecode 配置有利于浏览器和搜索引擎识别站点语言。
它的作用:
- 改变内部 RSS 模板中的
<language>
元素 - 改变内部别名模板中
<html>
元素的 lang 属性