Hugo使用
hugo是一个静态网站生成器, 类似hexo
本文假设读者已经了解静态页面的含义, 也接触过Jekyll, octopress或hexo.
目录
简述
与hexo类似, hugo提供了命令行工具
hugo # 编译生成静态文件
hugo help # 获取帮助信息
hugo new site # 初始化网站
hugo new post/*** # 创建文章
hugo server # 启动服务器
在万事俱备后, 添加新博文的组合拳基本上是
hugo new post/blog_name.md # 新建博文到content/post/目录下
hugo server -D # 启动服务器预览
hugo # 编译
然后将更新后的public
目录上传到pages或服务器上
第一次配置
安装
在windows下, 可以借助choco
choco install hugo -confirm
在linux下,
go get -v github.com/gohugoio/hugo
初始化网站
假设博客目录是/data/blog
cd /data/
hugo new site blog
cd blog
以下操作默认都在/data/blog
目录下
安装主题
装好hugo后, 必须安装主题, 才能开始编译
下方任选一个即可
git clone https://github.com/kakawait/hugo-tranquilpeak-theme.git themes/tranquilpeak
git clone https://github.com/vjeantet/hugo-theme-docdock.git themes/docdock
配置主题
以tranquilpeak为例, 拷贝参考配置文件到博客根目录下
cp themes/tranquilpeak/exampleSite/config.toml .
然后编辑该配置文件, 将博客名称, 作者等信息改成自己
如果配置文件里有themeDir
配置, 记得删除
另外, 配置文件中theme
这项要改为主题名称, 比如theme = "tranquilpeak"
(其实是主题所在目录的名称, 如果你是在themes目录下直接执行git clone而没有指定存放目录的话, 就应该是hugo-tranquikpeak-theme
)
测试配置效果
hugo new post/first.md
echo "## Content for Test" >> content/post/first.md
hugo server -D
打开浏览器localhost:1313
查看效果
编辑博文
hugo new post/第二篇博文啦.md
默认此命令生成的文件, 头部有3个metadata
- title
- date
- draft
对应的就是文章标题, 生成日期和是否草稿啦. 草稿文章只有hugo server -D
指令才会编译和显示
可以编辑archetypes/default.md
修改新文章模板
比如添加
categories: [],
tags: []
这样就更容易加标签和分类了
部署
编译生成的静态文件存放在public
目录下, 有两种选择将其部署到网上
- 利用代码托管网站的pages服务
- 将其放入web服务器资源文件目录下
利用pages服务对读者来说应该是轻车熟路了, 下面讲自行维护web服务的情况. 当然前提是你有一台自己的vps或服务器
计划是这样的
- 本地机器不参与编译环节, 也不维护public目录, 只维护content目录和一些配置文件, 比如config.toml, archtypes/default.md等
- 本地编辑源文件后上传到服务器
- 服务器自动编译, 将public拷贝到web服务器对应目录下, 或者hugo指定静态文件存放目录到web服务器对应目录下
上面提到的是常规做法, 实际上hugo集成了web服务器, 因此可以无需借助nginx或apache.
这里直接贴上守护程序的配置, 应该看得出做啥的吧
[program:hugo]
command=hugo server --baseURL=http://blogDomain --port=80 --bind=0.0.0.0 --disableLiveReload
directory=/data/blog
autostart=true
autorestart=true
user=root
log_stderr=true
redirect_stderr=true
stdout_logfile=/var/log/hugo.log
[program:hugo_draft]
command=hugo server -wD dev --baseURL=http://blogDomain_draft --port=8080 --bind=0.0.0.0
directory=/data/blog
autostart=true
autorestart=true
user=root
log_stderr=true
redirect_stderr=true
stdout_logfile=/var/log/hugo_draft.log
draft域名无需公网解析, 本地hosts即可
配合编辑器的sftp插件, 简直美滋滋
其实既然是本地编辑上传, 就无需维持一个draft状态和对应的服务器了. 只要上传动作是手动的, 那么默认上传的内容都是可以发表的即可.
使用nginx
当然, 开启一个hugo占用了80端口, 如果服务器还部署了其他服务, 就不能采用这种方式, 而是直接使用nginx代理public目录
比如nginx配置
server {
server_name blog.grunmin.tech;
listen 443 http2 ssl;
ssl on;
ssl_certificate /path/to/cer;
ssl_certificate_key /path/to/key;
root /data/blog/public;
}
那么, 要实现上传文件时实时更新public目录怎么办?
可以借助这个工具Watch来实现文件变更时自动编译
go get github.com/eaburns/watch
cd /data/blog
${GOPATH}/bin/watch -x public/ -t ${GOPATH}/bin/hugo
然后再将这条命令加入守护即可
从hexo中迁移
从hexo迁移到hugo有几点需要变更
- hexo的md文件使用yaml格式, hugo则是toml
- hexo中date字段不带时区, hugo带时区
- hugo中的隔断符严格要求是
<!--more-->
, hexo中的隔段符则可能是<!-- more -->
whatever, 下面附上迁移脚本, 改编自从 Hexo 迁移到 Hugo
// yaml_to_toml.js
const readline = require('readline');
const fs = require('fs');
const os = require('os');
const moment = require('moment-timezone'); // 需要通过 npm install moment-timezone 来安装
const timezone = 'Asia/Shanghai'; // 时区
const src = 'y'; // hexo .md 文件源目录
const target = 't'; // 目标文件目录
// 开始转换
readDir();
// 遍历目录
function readDir() {
// read all files in src
fs.readdir(src, function(err, files) {
files.map((filename) => {
// get the file extension
const extension = filename.substr(filename.lastIndexOf('.', filename.length));
if (extension === '.md') {
readFile(`${filename}`);
}
});
});
}
function readFile(filename) {
fs.readFile(`${src}/${filename}`, { encoding: 'utf8' }, function(err, data) {
if (err) {
return console.log('err: ', err);
}
const content = data.split('---');
let headContent = null;
let bodyContent = null;
if(content[0].length){
headContent = content[0]
bodyContent = content.slice(2).join('---')
} else {
headContent = content[1]
bodyContent = content.slice(2).join('---')
}
const head = headContent.split('\n');
// console.log('head: ', head);
let newHead = head.map((item, index) => {
// console.log('slpitHead: ', slpitHead(item, index, head));
return slpitHead(item, index, head);
});
newHead = newHead.filter((item) => {return item;});
const newBody = bodyContent.split('\n').map(item => replaceSummaryTag(item)).join(os.EOL)
// console.log('newHead: ', newHead);
const newContent = `---${os.EOL}${newHead.join(os.EOL)}${os.EOL}${os.EOL}---${os.EOL}${newBody}`;
const newFileName = filename.split('-').slice(3).join('-')
fs.writeFile(`${target}/${newFileName}`, newContent, {
encoding: 'utf8'
}, function(err) {
if (err) {
throw err;
}
console.log(`${newFileName} 生成成功!`);
});
});
}
function replaceSummaryTag(item){
if (item.indexOf('<!-- more -->') === 0){
return '<!--more-->'
}
return item
}
function slpitHead(item, index, head) {
// title
if (item.indexOf('title:') !== -1) {
if(item.split('"').length === 3){
return `title: ${item.split('title:')[1].trim()}`;
}
return `title: "${item.split('title:')[1].trim()}"`;
}
// date
if (item.indexOf('date:') !== -1) {
return `date: ${(moment.tz(item.split('date:')[1], timezone)).format()}`;
}
// tags
if (item.indexOf('tags:') !== -1) {
// console.log('tags...');
const tags = [];
if(item.length >5){
const c = item.split(':')[1].split('').filter(o=>o !== ' ').join('');
if(c){
tags.push(item.split(':')[1].split('').filter(o=>o !== ' ').join(''))
}
}
for (let i=index+1; i<head.length; i++) {
if (head[i].indexOf('-') !== -1) {
// console.log('head[i].split('-')[1]: ', head[i].split('-')[1]);
tags.push(head[i].split('-')[1].trim());
} else {
break;
}
}
// console.log('tags: ', tags);
return `tags: ${JSON.stringify(tags)}`;
}
// categories
if (item.indexOf('categories:') !== -1) {
const categories = [];
if(item.length >11){
const c = item.split(':')[1].split('').filter(o=>o !== ' ').join('');
if(c){
categories.push(item.split(':')[1].split('').filter(o=>o !== ' ').join(''))
}
}
for (let i=index+1; i<head.length; i++) {
if (head[i].indexOf('-') !== -1) {
categories.push(head[i].split('-')[1].trim());
} else {
break;
}
}
// console.log('categories: ', categories);
return `categories: ${JSON.stringify(categories)}`;
}
return false;
}
其他问题
备份
如果选择了pages托管, 那么只需记得将源码也上传一份即可, 如果是放在自己服务器, 可以跑一个定时任务, 如果当天有变更, 则通过git push到某个仓库进行备份
比如在博客目录下添加一个备份脚本backup.sh, 内容是
git add .
git commit -m "update in `date +'%Y-%m-%d %H:%M:%S'`"
git push origin master
然后添加一个计划任务
0 0 * * * cd /data/blog && sh backup.sh
不过, 如果是通过git的方式备份, 添加的主题仓库必须作为submodule, 如果不是则要先删除, 等初始化后重新下载
git submodule add https://github.com/kakawait/hugo-tranquilpeak-theme.git themes/tranquilpeak
语法高亮
语法高亮与主题的关系大一些, 以tranquilpeak主题为例. 该主题默认使用highlight.js做语法高亮. highlight.js脚本只包含一部分语法高亮的规则, 某些语言被独立出去了, 比如go, 就必须额外导入go.min.js文件, 完整文件路径像这样
https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/languages/go.min.js
有几种方式可以导入该文件, 第一是修改该主题下目录下的layout/partials/script.html
文件, 第二是拷贝一份修改版到博客根目录下的layout
目录. 不过tranquilpeak提供了一个配置参数, 可以很方便的导入该文件.
方法就是修改config.toml
文件, 找到[[params.customJS]]
标签, 在下方添加如下一行即可
customJS = ["https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.8.0/languages/go.min.js"]