TOC
之前学着用hexo和github page建了一个博客,虽然购买了几年的域名,但是几乎处于荒废状态。也没有研究具体的用法,最近周围的人很多都开始用jekyll来做一些静态的网页用来当自己的简历或者写教程,所以我也有了重新开始折腾博客的想法。最终我选择了用Hugo,只是因为它很快。和Hexo还有Jekyll一样,Hugo也是一个用于生成静态网页的框架。不同的是Hugo使用Go语言写的,Hexo和Jekyll分别用的是Node.js和Ruby。我选择了这个CleanWhite的主题,和之前我hexo的主题很像。你也可以不用主题,直接在layout文件夹里定义自己的模板。
跟着网上的教程安装并配置好主题后,我简单的研究了一下hugo的结构和用法,尝试去理解一些技术层面的东西,但是并不深入。
Content
所有的文章都在content文件夹下以markdown格式存在,使用 hugo new filename.md
可以直接在content下生成一个空白的模板。可以将文件生成在content下的子文件夹,不存的文件夹在hugo会生成。产生的页面则是在对应的文件夹名下。例如,hugo new dir1/filename.md
的对应页面是domainname.com/dir1/filename
。
Front Matter
Front Matter是markdown文件最上方用来预先定义参数的内容,下面是YAML的格式,TOML格式的语法非常相似,但是使用加号分隔,并且用等号赋值。Hugo支持YAML,TOML和JSON格式,Jekyll只支持YAML。
---
title: "title"
date: 2020-11-28
author: "anyone"
tags: ["tag1"]
---
Front Matter 提前指定了一些变量(predefined var),在html中调用, 如 {{ .Title }}。Hugo提供了很多预定义的变量,如title,date,image,categories,layout等。你可以有自己在front matter里定义自己的变量,Hugo会全部放到一个Param变量,然后通过{{ .Param.var }}来访问。你可以用变量weight来控制文章在listing页面的排序,想要置顶就是weight:1
.
Archetypes
Archetypes是创建新的post文章的模板文件,也是md文件,就在archtypes文件夹下面。
---
title: "{{ replace .TranslationBaseName "-" "-" | title }}"
date: "{{ .Date }}"
draft: true
author: "JZ"
tags: ["tag1", "tag2"]
categories: ["Note" ]
---
** insert things here **
可以定义多个archtypes作为不同类型文章的模板,例如有一个post.md。你可以通过hugo new post/my-post.md
创建这个文件。
Taxonomies
这个是一个用于对文章进行分组的功能,让用户可以根据文章的一些属性进行分类,也方便查询和阅读。Hugo默认的Taxonomies有tags和categories,都可以在front matter里直接定义,hugo会为每个标签或者category生成单独的页面。具体的用法取决于模板定义,我用的这个模板,会将不同的categories的文章放到一个单独的列表页面,在header里可以进行访问。
当然你也可以添加自己的taxonomies,比如说你想根据当天的天气,心情来分类,可以在front matter里定义:
---
title: "{{ replace .TranslationBaseName "-" "-" | title }}"
date: "{{ .Date }}"
tags: ["travel", "photo"]
categories: ["Life" ]
moods: ['happy']
weathers: ['sunny']
---
但是因为不会默认的taxonomies,hugo不会为这个分类单独生成一个页面,所以需要在配置文件config.toml
里设置。
[taxonomies]
tag = "tags"
category = "categories"
mood = "moods"
weather = "weathers"
Template
我用的是别人写好的主题,但是其实主题也是别人写好的模板。在hugo里有两种模板,一种是列表模板,一个是single模板。在layout/_default
文件夹下的list.html
和single.html
就是列表页面和single页面的模板。列表页面用于显示多个文章,single页面就是显示一篇文章。这些页面都共享一些元素,比如说header,footer等。每一篇文章的页面基本结构都是一样的,除了文章本身的内容。所以用到模板就可以只建好一个html页面,然后用markdown解析的内容替换模板中的一些变量。
还有一些页面你可以自己定义,主题里的layout会被根目录里的模板覆盖。主页其实也是一个列表页面,如果你不想你的主页是一个简单的列表页面,或者你想在模板上进行改进。你可以在layout/index.html
再创建一个home page模板。
如果你想对在content文件夹下的文章用单独的模板,可以使用section template。只需要在layout下单独添加single.html
或者list.html
。简单的说就是content里文件夹里的md文件会调用layout文件夹下对应文件夹名里的模板html。另外,因为博客网页的结构非常单一,所以还可以用一个base template来减少代码量。在layout/_default
下的文件baseof.html
就是整个网页的基本框架的模板。在baseof.html
里,可以用到一个特殊的hugo实体block, 在html里可以插入一些block来占位,然后在另一个html里定义这个block的内容。
还有一种模板的用法是partial templates,是一种可以模块化的方法。可以把一个页面的元素拆分开来,将页面里的header,footer或者sidebar单独写成一个文件。这些partial的模板要放在layout/partials
下面。例如,你有一个header.html
的partial模板:
<h1>{{.Title}}</h1>
<p>{{.Date}}</p>
然后在single template里,你想要用这个header模板,就要使用partial这个函数,{{ partial "header" .}}
, 这里的点代表你想要使用的范围是所有,这样你才可以访问到partial里所有的变量。
{{ partial "header" . }}
{{.Title}}
这是一个baseof.html
模板
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
Top of baseof
<hr>
{{ block "main" . }}
{{ end }}
<hr>
bottom of baseof
</body>
</html>
在single.html
模板中定义对应的main block:
{{ define "main" }}
this is the single template
add any content here
{{ end }}
你可以在baseof里写好通用的block,也可以在单个模板里重写,但是这个功能大大减少了代码的冗余。
Variable
在之前已经有在html里调用变量的例子了,基本上就是用双花括号。例如要在html中插入标题和日期:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>{{ .Title }}</title>
</head>
<body>
Today is {{ .Date }}
This is the link to the file {{ .URL }}
</body>
</html>
在front matter可以有更多的自定义变量,通过{{ .Param.Var }}
访问。除了在front matter 里定义,你可以在html里直接创建变量。
{{ $myVar := "aString" }}
<h1>This is a custom var: {{ $myVar }}</h1>
Hugo还有很多特有的变量可以在html里调用,具体有哪些变量可以在官方文档里看到。
Function
Hugo预先写好了一些函数方便使用,函数只能在layout下的模板文件里使用。用法也很简单:
{{ funcName param1 param2 .. paramN}}
有一些处理字符串的函数比较常用,如truncate会截断字符串到指定长度:
{{ truncate 10 "This a way long long long long way to go" }}
hugo也可以写循环:
{{ range .Pages }} #.Pages 是一个hugo变量,代表当前section的page数。
{{ .Title }} #这里打印出所有文章
{{ end }}
hugo所有的函数也可以在这里查到。
当然,hugo也可以有if-else,也是需要放在双括号里。
{{ $a := "apple" }}
{{ $b := "orange" }}
{{ if not (eq $a $b) }}
True
{{ else }}
False
{{ end }}
这个条件执行语句可以用在style里,例如你列出了所有的文件,但是想要当前标黄页面名。结合for loop和if:
<h1>Single template</h1>
{{ $title := .Title}} #当前页面名
{{ range .Site.Pages }}
<li><a href="{{ .URL }}" style="{{if eq $title .Title }} background-color: yellow; {{end}}"></a>{{.Title}}</li>
Data files
在根目录下,我还看见了一个data文件夹,是空的。我不太懂怎么用,通常动态网页会有一个对应的数据库,但是hugo用于生产静态网页,data文件夹放的都是YAML,TOML或者JSON格式的文件。例如你存了一些JSON格式表格信息,可以通过for loop在模板里访问到这个文件通过变量{{ .Site.Data.filename }}。这个应该很少用的。
Shortcodes
shortcodes算是hugo一个比较高级的功能了,我应该不怎么用到。markdown来写文档很简单,如果要在页面嵌入像视频这样的复杂的元素就需要在markdown中插入一大段html。这样看起来并不美观,而且markdown并不支持和html共存,需要进行解析。shortcodes只是用很小一段代码标记,就可以在网页生成的时候,用对应的html代码去替换这个区域。具体的html模板都是放在layout/shortcodes/
下。
比如说建立了一个youtube嵌入视频的hmtl模板layout/shortcodes/youtube.html
<style>
#biliplayer {
width: 100%;
height: 600px;
}
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
#biliplayer {
width: 100%;
height: 250px;
}
}
</style>
<div class="embed video-player">
<iframe class="youtube-player" type="text/html" width="640" height="385" src="https://www.youtube.com/embed/{{ index .Params 0 }}" allowfullscreen frameborder="0">
</iframe>
</div>
在markdown文档中,只用调用这个模板并提供对应视频的AV号就可以了。
## here is a youtube video.
{{< youtube r_Ws-jW1Rz4 >}}
借用一下同学的视频。
简单的想,shortcodes给我的感觉有点像自定义的函数,然后可以在markdown里直接调用。例如你可以写一个myshortcode.html
在shortcodes文件夹下:
<p style="color:{{index .Params 0}}">This is a string that can be any color specified by shortcodes</p>
然后在md文件中调用它:
{{< myshortcode brown >}}
也可以不用参数传递的形式传入参数,可以用shortcodes的标签包括内容。
{{< myshortcode >}}
anytext that are not been rendered.
{{ /myshortcode}}
如果你需要传入的字符被render:
{{% myshortcode %}}
**bold text**
{{ /myshortcode}}
我没有很深入的研究更多的用法,希望以后有机会可以用到。
Go public
使用hugo server
命令可以本地预览网页,最终还是要生成一堆html用于放在自己的或者github的服务器上。只需要运行hugo
,会生成一个public文件夹包含所有的html。把这个文件夹上传至服务器就可以运行了。我是放在github上的,我已经有一个github page的仓库.同时我也想把这个hugo的内容也上传到github。可以通过git submodule
将生成的public子文件夹作为username.github.io
这个远程项目,首先把public文件夹删除。
git submodule add https://github.com/bakeronit.github.io public
这时目录下会产生一个.gitmodules
文件:
[submodule "public"]
path = public
url = https://github.com/bakeronit/bakeronit.github.io.git
然后可以创建一个deploy.sh
文件:
#!/bin/bash
echo -e "\033[0;32mDeploying updates to GitHub...\033[0m"
# Build the project.
hugo # if using a theme, replace with `hugo -t <YOURTHEME>`
# Go To Public folder
cd public
# Add changes to git.
git add .
# Commit changes.
msg="rebuilding site `date`"
if [ $# -eq 1 ]
then msg="$1"
fi
git commit -m "$msg"
# Push source and build repos.
git push origin master
# Come Back up to the Project Root
cd ..
直接运行这个脚本就可以了,其实主题也可以通过submodule。。但是要注意删除submodule
需要手动删除,不能直接rm
。
接下来我想把hugo源文件也上传到github,这时候我不想要把public也提交上去,就要用到.gitignore
配置文件,在里面写入不想上传的文件名。
.DS_Store
/public
然后把这个项目推送到github,中间发生一个小插曲,原来最近github把默认的branch名改成了main
,以前是master
。现在要push
到main branch
了。
Cusom domain
如果你想要用自己的域名,只需要在static文件夹下写一个CNAME文件,内容是自己的域名。这样每次hugo都会将CNAME拷贝到网页项目的根目录,然后就可以通过你的域名访问这个github page了。不过首先不要忘了在域名解析服务商那里添加几条github的记录,我几年前用的dnspod,现在把找回来居然是腾讯云了,它有A记录的数量限制。github有4条A记录,最后我直接在godaddy上搞了。
#A record
185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
检查是否解析成功了:
> dig EXAMPLE.COM +noall +answer
EXAMPLE.COM 3600 IN A 185.199.108.153
EXAMPLE.COM 3600 IN A 185.199.109.153
EXAMPLE.COM 3600 IN A 185.199.110.153
EXAMPLE.COM 3600 IN A 185.199.111.153
另外,如果有强迫症想要一个绿🔐,github现在提供Let’s Encrypt免费认证了。其实具体是什么我也不懂。但是只用在网页项目的配置页面勾选Enforce HTTPS就好了,有可能要等一段时间才行,我睡了一觉起来就好了。