曾国藩:一勤天下无难事

GitHub + Hugo to Build a Personal Blog

2019.02.23

-

自己搭博客的N个理由

  • 你的笔记非常值钱,丢了就等于丢了N年工作经验。
  • 大多数博客网站都满足不了你:
    • 倒闭/停止服务/被删库时,你多半没备份。
    • 格式互不兼容,导入导出困难,复制粘贴会乱。
    • 富文本编辑器极其难用。
    • 可配置的地方不够,你讨厌的功能一堆。
  • 可以使用 Markdown 写博文:
    • 任何一个文本编辑器都能写,随时随地。
    • 足够沉浸,让你忘记格式,专注内容。
    • 备份容易:
      • GitHub, GitBook, 印象笔记,CSDN,博客园,简书等都支持,到处复制粘贴也能得到大致相同的格式。
      • 纯文本本身也有足够可读性,网站/软件不支持也无所谓。
  • GitHub 提供免费空间和 CDN,站点放 GitHub 仓库也方便做版本控制。
    • 用来当印象笔记的一个备份网站,写作的同时加深印象
    • 方便自己,方便他人
  • 可以作为学习新技术的试验田。

注册 GitHub

先注册一个 GitHub 账号。

用户名会成为网址的一部分,以下为建议 * 最好全英文小写 * 不需要空格 * 不需要太长 * 建议使用自己的名字,方便好记。

例:用户名 adolf,对应网址 adolf.github.io


安装Git

Mac

brew install git

PC 下载安装 Git ,全用默认设置,然后打开 Git 终端。

  • 默认工作目录是 Git 安装目录下的 mingw64 文件夹。
  • 路径分隔符使用 / 或

设置 Git 默认用户信息

git config --global user.name "adolf"
git config --global user.email "adolf@qq.com"
# 使用 GitHub 注册的用户名和邮箱

这台机器上的每个项目提交时默认都会用这些信息。


创建 GitHub Pages

在 GitHub 上新建仓库(repository):

  • 名字必须为 username.github.io ,如:adolf.github.io

只要往里面提交一个 index.html 文件,就能通过 https://adolf.github.io 访问了。

不过除了前端,没几个人愿意碰 HTML 和 CSS,这么建站实在太2000年代了,生成器用起来。


使用静态网站生成器搭建站点

个人网站/博客通常只需要简单的静态页面,这类工具 正好可以把 Markdown 文档转换成网页,非常方便。

这里选择 Hugo,特点是生成速度非常快(构建5000篇文章不用10秒),安装配置也不算复杂,适合不想折腾的人。

它最实用的就是实时预览功能,不需要发布到 Github 就能看到改动。

安装

Mac

brew install hugo
# 查看版本
hugo version
# 查看帮助

PC 下载后解压,把 hugo.exe 的路径加进环境变量 Path 就行。


新建站点

假设站点文件想放在当前目录的 hugo-blog/ 目录下:

hugo new site -f yaml hugo-blog
# -f, --format {yaml|json|toml}    指定 config 和 front matter 的格式,默认 toml。
# 推荐 yaml 格式。

生成的目录结构如下:

$ cd hugo-blog
$ tree
.
├── archetypes  # 博文模板
│   └── default.md  # 默认模板文件
├── config.yaml  # 主配置文件
├── content  # 存放博文,里面的子目录叫做 section。
├── data  # 生成网站时的配置
├── layouts  # 网页框架,放在这里的文件会比主题里的同名文件优先,可以在不动主题源码的情况下覆盖部分设置。
├── static  # 静态资源,这目录下的文件会原封不动的拷到站点根目录下。
└── themes  # 主题

https://gohugo.io/commands/hugo_new_site/

https://gohugo.io/getting-started/directory-structure/


下载主题

默认不带主题,从 这里 挑喜欢的下载。

我用的是 Even

git clone https://github.com/olOwOlo/hugo-theme-even themes/even

修改配置文件

编辑 config.yaml,默认值如下:

baseURL: http://example.org/  # 替换为你的网址
languageCode: en-us  # 中文博客建议改为 zh-cn。如果文章内容不是这里指定的编码,Chrome 会弹出要不要翻译页面的提示。
title: My New Hugo Site  # 替换为你的博客标题
theme: even  #替换为刚才的主题

或者也可以使用even主题自带的配置,默认在 even github 的页面已经给出,大家可自行操作:

Important: Take a look inside the exampleSite folder of this theme. You'll find a file called config.toml. To use it, copy the config.toml in the root folder of your Hugo site. Feel free to change it.

编辑默认模板

在 archetype/ 下新建 .md 文件,如果文件名跟新建文章时的 SECTIONNAME 一致,则该 section 下的文章都会套用这模板。

找不到匹配的 section 才会套用 default.md。

default.md 的默认 front matter:

---
title: '{{ replace .Name "-" " " | title }}'
date: {{ .Date }}
draft: true
---

添加常用 front matter(加在分隔符之间):

slug: {{ .TranslationBaseName }}  # URL 路径的最后一部分
# .TranslationBaseName 为不带语言标识符的文件名。比如文件名为 foo.en.md,得到 foo
tags: []
categories: []

另外 Even 主题还配置了一些特有的参数,参见它的 默认模板。

https://gohugo.io/content-management/archetypes/

https://gohugo.io/variables/files/


调整样式

如果对主题某些地方不满意,又不想直接改主题源文件,可以去 themes/<主题名>/layouts/ 看看都有什么文件,把要改的拷到 layouts/ 下。

文件查找顺序大致如下,同名文件在 layouts/ 下的比主题里的优先,匹配到 section 名的比 _default 优先。

layouts/<section>/...
themes/<主题名>/layouts/<section>/...
layouts/_default/...
themes/<主题名>/layouts/_default/...

https://gohugo.io/templates/lookup-order/#examples-layout-lookup-for-regular-pages


新建博客文章

hugo new post/2016-07-19-first.md
# 格式:<SECTIONNAME>/<FILENAME>.<FORMAT>

可以看到在 content/ 下生成了 post/ 目录,post/ 下有 2016-07-19-first.md 文件。

推荐文件名加上日期前缀,因为通常所有博文都放在同一个目录下(这样配置最简单),带日期一眼就能区分新旧文章。

这操作经常用,建议写成脚本:(例如叫做 new)

自动加上当天日期做前缀 section 名默认叫 post 因为上面在配置文件里已经设置了把日期前缀提取到 URL 路径,front matter 里的 slug 去掉前缀。

#!/bin/bash
[[ -z "$1" ]] && echo "Usage: $(basename "$0") FILENAME(without suffix) [SECTIONNAME]" && exit 1
section_name=${2:-post}
date_prefix=$(date +%Y-%m-%d-)
file_path="${section_name}/${date_prefix}$1.md"
hugo new "${file_path}"
sed -i '.bak' "s/slug: ${date_prefix}/slug: /" "content/${file_path}"
rm -f "content/${file_path}.bak"
# Mac 的 sed -i 的第1个参数必须为备份文件后缀名

编辑博文

用文本编辑器打开刚才生成的文件,可以看见类似如下内容(YAML格式):

---
title: "2016 07 19 First"
date: 2018-02-10T23:16:02+08:00
draft: true
---

(或默认的 TOML 格式):

+++
date = "2016-07-19T00:12:34+08:00"
draft = true
title = "2016 07 19 first"
+++

像这样的出现在每篇文章前的元数据叫 front matter,--- 之间包着的内容会解析为 YAML,+++ 之间包着的内容会解析为 TOML。

在下面的空白处用 Markdown 格式写正文,如:

## Hello Hugo
坚持写博客的好处:
- 记录心得
- 整理思路
- 分享交流
- 求职展示

完整文件见 这里

https://gohugo.io/content-management/front-matter/


资源文件

放到 static/ 下,这目录下的所有文件和目录都会原封不动的拷到站点根目录下。

我习惯用的目录结构:

.
├── CNAME
├── css  # CSS 文件目录
├── googleXXX.html  # Google Analytics 的验证网页
├── img  # 图片目录
│   ├── reward  # 特定的主题专门建目录
│   │   ├── alipay.jpg  # 支付宝收款二维码
│   │   └── wechat.png  # 微信赞赏二维码
│   └── post  # 一般的博文配图按年月日建目录
│       └── 2018
│           └── 02
│              └── 28
├── js  # JS 脚本目录
└── robots.txt

【注意】

  • 博文里引用图片时要写完整 URL,前面是实际的域名,后面是相对 static/ 目录的路径。
    • 例:微信打赏
  • Hugo 不会帮你压缩图片,也不提供缩略图,建议提交前用工具处理图片。
  • 不重要的图可以压成 70% jpg,宽度缩到 600px。颜色少可以试试 8色 png。
  • 命令行工具有 imagemagick 用来裁剪和压缩图片,转格式等,exiftool 用来去掉 EXIF 信息。

本地预览

运行 hugo server,就会启动一个很简单的 HTTP 服务器。浏览器打开 localhost:1313 就能看到生成的网页,样式跟发布到线上完全相同。

之后文件有任何改动都会自动重新构建和刷新浏览器页面。

【注意】

运行 hugo server 时,当前工作目录必须为站点根目录(包含配置文件),否则提示 Error: Unable to locate Config file. Hugo 每次生成站点时不会删旧文件,因此推荐把预览和发布目录分开,并且每次生成前把旧目录删除。 这操作经常用,建议写成脚本:(例如叫做 dev_preview)

#!/bin/bash
[[ -d dev ]] && rm -rf dev
hugo server --buildDrafts --destination dev --disableFastRender
# -D, --buildDrafts[=false]    文章的默认状态是草稿,草稿默认不会构建,必须加上这参数才会生成页面。
# -w, --watch    文件有改动时自动重新构建并刷新浏览器页面。(默认就带这个,不传也行)
# -d, --destination DIR    输出目录。不传这参数的话构建出来的文件只会放在内存里。
# --disableFastRender    有改动时触发完整构建。反正 Hugo 非常快,几百毫秒根本感觉不到。

ctrl + c 结束 hugo server 。


生成发布页面

首先把要发布的文章的 draft 属性改为 false,运行 hugo。

执行后会生成 public/ 目录,可以看到之前的 Markdown 文件转换成了文件夹 + HTML 文件。

这操作经常用,建议写成脚本:(例如叫做 release)

#!/bin/bash
if [[ -d public ]]; then
    GLOBIGNORE=*.git
    rm -rf -v public/*
fi
hugo
if [[ -n "$1" ]]; then
    cd public
    git add -A
    git commit -m "$1"
    git push
else
    echo
    echo "[WARN] Files will NOT be uploaded to Github without adding comments."
    echo "Usage: $(basename "$0") COMMIT_COMMENTS"
fi

再用 hugo server 检查一下有没有 draft 忘了改,确定文章能看到就可以发布了。

这步也可以写成脚本:(例如叫做 preview)

#!/bin/bash
hugo server --disableFastRender

本地图片由于还没上传,肯定全是叉。介意的话可以先把图传上去,验证过路径都写对了才发布网页。


发布到 GitHub

可以装 GitHub Desktop 或 SourceTree 等客户端,或者直接命令行:

cd public
git init
git remote add origin "git@github.com:keithmork/keithmork.github.io.git"  # 替换成你的 GitHub Pages 仓库地址
git add -A
git commit -m "first commit"
git pull
git push -u origin master
# 注意:要用 SSH 的仓库地址才能用公钥,如果用了 HTTPS 的仓库地址,必须每次输用户名密码。

之后会提示输入在 GitHub 注册的邮箱和密码。

提交成功后,浏览器打开https://adolf.github.io,就能看到刚才的页面了。

第一次麻烦点,之后每次提交都很简单:(已经写在上面的 release 脚本里,参数传 true 就会提交和发布)

git add -A
git commit -m "XXX"
git push

使用 SSH 密钥登录 GitHub

每次发博文都输用户名密码太麻烦,用密钥代替密码就方便多了。

前提是机器只有你一个人用。

生成SSH密钥对

  • 提示 Enter file in which to save the key 时直接回车,使用默认设置。
    • 文件名不用改,GitHub 连接时只认 id_rsa
  • 提示 Enter passphrase 和 Enter same passphrase again 时,可以直接回车,不使用口令(否则每次提交时会要求输入口令)。

https://help.github.com/articles/generating-an-ssh-key/


添加 SSH 公钥到 GitHub

复制公钥文件(默认 ~/.ssh/id_rsa.pub)的内容。 登上 GitHub,在个人设置里找到 SSH and GPG keys,新建 SSH key,粘贴进去。 取个容易识别的名字,如 Mac-Home PC-Work 等,保存。 测试是否成功:

ssh -T git@github.com  # 用户名就是git,不用改。

# 如果报错,这样看详细信息:
ssh -vT git@github.com
# 看到以下讯息就是成功了:(虽然命令返回 1)
# You've successfully authenticated, but GitHub does not provide shell access.

看到 Are you sure you want to continue connecting 时输 yes 回车,然后就可以了。

如果依然每次都问用户名密码,可能是当初加仓库地址时用了 HTTPS 格式,改为 SSH 格式的地址就好了:

git remote set-url origin git@github.com:keithmork/keithmork.github.io.git

发布 Hugo 工程源文件到 GitHub

源文件比生成的发布文件重要得多,必须备份到 GitHub。发布文件丢了随时重新生成,源文件丢了就没了。

在 GitHub 新建仓库,例如叫 hugo-blog,不要勾选创建 README.md 。 在工程根目录下创建 .gitignore 文件,写上不需要备份的目录和文件,例:

public
themes
dev
.git
.DS_Store
*.bak
*_bak
*.old
*.log

如果想写项目简介,创建 README.md 文件。 和之前类似的操作:

git init
git remote add origin "git@github.com:adolf/hugo-blog.git"  # 替换成你的 GitHub 仓库地址
git add -A
git commit -m "first commit"
git pull
git push -u origin master

如果忘了写 .gitignore,把 public 和 themes 也提交了上去,会发现它们被认为是 submodule (因为里面有 .git 目录)。即使之后设置忽略它们,每次里面的文件有更新时都会出现烦人的子模块状态变更的记录。

解决方法:先把那2个目录复制到别的地方,把它们删掉,写好 .gitignore,在 .git/config 里删掉 [submodule] 相关内容,提交,再把它们搬回来。


遇到的问题

  • 文章时间一直不对,修改config.toml文件,将以下参数修改成:

    enableGitInfo = false
    dateFormatToUse = ""
    
  • 打赏处的二维码一直不显示

    [params.reward]                                         # 文章打赏
    enable = true
    wechat = "https://emor.me/img/reward/wechat.jpg"           # 微信二维码
    alipay = "https://emor.me/img/reward/alipay.jpg"           # 支付宝二维码
    

结束语

到这里,一个属于自己的静态博客基本成型了。

可能样式、功能或别的细节不能完全令人满意,但那些基本不影响写文章,可以先专注于输出内容,其他留到以后慢慢优化。

本文源链接是Haunted Hovel - 闹鬼小屋