个人博客的诞生

1 前言
1.1 概述
前前后后花了超过一个月的时间进行调研、选型、测试,终于上线了目前的这个版本,最终基于hugo搭建,主题为loveit的静态博客,评论系统使用基于leancloud的valine,搜索引擎采用algolia,发布在cloudflare的pages上面,下面简要讲解一下
1.2 初探
一开始的思路是使用cloudflare的worker搭建个人博客,参考链接如下
https://github.com/Arronlong/cfblog-plus
https://blog.gezhong.vip/article/009000/update-log.html
当时尝试的时候只有基础版本,虽然功能已经很强大了,但是不支持搜索功能,评论系统的引入也比较硬,另外虽然worker的免费版本调用数量足够高,但还是有限制,而且主题模板太少了,感觉像是半成品,最后就没有采用。另外如果是运行在worker上的,除了KV的限制,还不支持上传图片,所有图片只能采用链接插入,我还专门找教程做了一个简易的图床,参考链接如下:
https://wlnxing.com/archives/49.html
https://mitsea.medium.com/backblaze-b2-cloudflare-%E6%90%AD%E5%BB%BA%E5%9B%BE%E5%BA%8A-94afa1f762dc
只能说cf的worker真的是强大。。。但是放博客图片每次都要做成链接也不是特别便捷(而且我用cf pages也无限流量)
1.3 进阶
最后用的方案就是现在看到的样子,这里放一下参考链接,详细配置细节后面展开
使用hugo的loveit主题:
https://bore.vip/archives/hugo-theme-LoveIt/
使用的搜索引擎的教程:
https://edward852.github.io/post/hugo%E6%B7%BB%E5%8A%A0algolia%E6%90%9C%E7%B4%A2%E6%94%AF%E6%8C%81/
评论系统方面参考:
2 配置环境
2.1 安装hugo
在github上下载hugo,找个地方解压缩后配置到PATH中(我是win)环境
2.2 创建项目并设置主题
找了一个教程做参考,主要git命令如下
hugo new site my_website
cd my_website设置主题,主题可以通过github搜索“hugo theme”并按star排序来参考热度
git init
git clone https://github.com/dillonzq/LoveIt.git themes/LoveIt2.3 基础配置
baseURL = "/"
# [en, zh-cn, fr, ...] 设置默认的语言
defaultContentLanguage = "zh-cn"
# 网站语言, 仅在这里 CN 大写
languageCode = "zh-CN"
# 是否包括中日韩文字
hasCJKLanguage = true
# 网站标题
title = "我的全新 Hugo 网站"
# 更改使用 Hugo 构建网站时使用的默认主题
theme = "LoveIt"
[params]
# LoveIt 主题版本
version = "0.2.X"
[menu]
[[menu.main]]
identifier = "posts"
# 你可以在名称 (允许 HTML 格式) 之前添加其他信息, 例如图标
pre = ""
# 你可以在名称 (允许 HTML 格式) 之后添加其他信息, 例如图标
post = ""
name = "文章"
url = "/posts/"
# 当你将鼠标悬停在此菜单链接上时, 将显示的标题
title = ""
weight = 1
[[menu.main]]
identifier = "tags"
pre = ""
post = ""
name = "标签"
url = "/tags/"
title = ""
weight = 2
[[menu.main]]
identifier = "categories"
pre = ""
post = ""
name = "分类"
url = "/categories/"
title = ""
weight = 3
# Hugo 解析文档的配置
[markup]
# 语法高亮设置 (https://gohugo.io/content-management/syntax-highlighting)
[markup.highlight]
# false 是必要的设置 (https://github.com/dillonzq/LoveIt/issues/158)
noClasses = false2.4 文章创建
hugo new posts/个人博客的诞生.md完成后编辑个人博客的诞生.md的内容,将draft调整为false,标签和分类也直接写,并在其中编辑内容,示例如下:
title: "个人博客的诞生"
date: 2021-03-15T18:35:13+08:00
draft: false
tags: ["hugo", "blog", "cloudflare"]
categories: ["基础教程"]
featuredImage: "/images/个人博客的诞生/title.jpg"
featuredImagePreview: "/images/个人博客的诞生/title.jpg"
description: "简要描述了你所看到的博客是如何从0-1诞生的"
typora-root-url: ..\..\static置顶<!--more-->同时撰写description,或直接撰写summary,都可单独展示摘要,不配置默认为前70个字符
另外可以在利用 https://realfavicongenerator.net/ 生成网站图标并解压缩后放置到/static路径下,图片可以统一放在/static/images路径下
编辑器推荐Typora,注意如果本地编辑器使用了Typora撰写markdown,需要在"格式"-“图像"下拉框中选定"设置图片根目录"并设置到/static路径,这样才能自动渲染显示图片
2.5 本地预览
使用命令启用本地预览,注意实时编辑会改变预览输出
# 本地预览
hugo server
# 添加draft的预览
hugo server -D
# 自定义端口测试
hugo server -p=1234
# 开启评论系统、cdn等
hugo server -e production2.6 自建图床
主要参考这个教程,图片效果如下(测了几次,某些情况下加载速度好像会稍微慢一点,不够好在也不用自建服务器):
可以考虑用在单图片超过25M的时候使用,而且有防火墙防盗链配置整体效果还是不错的,当然受限于网络状况也有可能图片加载不出来,链接独立还不方便cdn反代,
另外涉及到图片压缩的话,实测tinypng效果还不错
2.7 文章特性
hugo不仅仅支持基础语法,还可以通过shortcodes支持大量拓展功能,具体可以参考以下链接:
3 发布博客
3.1 准备cloudflare pages
略过域名注册和dns解析等,直接来看cloudflare的pages的教程 ,也可以选择别的(github pages / Netlify等),主要考虑到cf的抗cc能力太强了,而且除了单文件大小上限25M外几乎没有限制,
3.2 环境变量
注意需要在pages中的“设置”-“环境变量”下添加“HUGO_VERSION” = “0.81.0”(使用的版本)不然默认会使用较老的版本导致部署失败,建议同时设置“PYTHON_VERSION” = “3.7”,便于后续融合python脚本(如果本地编译则不需要设置cf pages的环境变量)
3.3 内容加密
主要参考教程是来自:
使用了hugo_encryptor这个开源项目,大概效果如下:
文章的部分内容被密码保护:
密码是“PASSWORD”,考虑更新及时性还可以另外写个脚本部署的时候update一下依赖的py文件和html模板
3.4 部署方式
cf关联github后会自动检测并部署,但融合加密后使用cf的远端编译总是不成功,后面考虑到本地python环境齐全,索性改成本地编译完后推送public到cf发布,并将cf中“构建与部署”中的“构建目录”留空,推送github前运行deploy.sh文件,再hugo server可以预览编译后的站点
3.5 搜索系统
实测lunr太慢,algolia还行,algolia注册记得选香港会更快,除了配置[params.search],还需要配置index,主要参考了以下教程的内容:
https://edward852.github.io/post/hugo%E6%B7%BB%E5%8A%A0algolia%E6%90%9C%E7%B4%A2%E6%94%AF%E6%8C%81/
记得在config.toml配置文件中添加:
# 配置 Algolia index
[outputs]
home = ["HTML", "RSS", "Algolia"]
[outputFormats.Algolia]
baseName = "algolia"
isPlainText = true
mediaType = "application/json"
notAlternative = true
[params.algolia]
appId = "xxx"
indexName = "xxx"
searchOnlyKey = "xxx"根目录下 layouts/_default (没有就新建) 文件夹中新建 list.algolia.json 文件,内容如下:
{{/* 生成Algolia搜索索引文件 */}}
{{- $.Scratch.Add "index" slice -}}
{{/* content/posts或content/post目录下的博文才生成索引 */}}
{{- range where (where .Site.Pages "Type" "in" (slice "posts" "post")) "IsPage" true -}}
{{- if and (not .Draft) (not .Params.private) -}}
{{- $.Scratch.Add "index" (dict "objectID" .File.UniqueID "url" .Permalink "content" (.Summary | plainify) "tags" .Params.Tags "lvl0" .Title "lvl1" .Params.Categories "lvl2" "摘要") -}}
{{- end -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}另外还需要用到npm的atomic-algolia包来自动上传,创建.env环境,npm run algolia可以放到deploy.sh里面发布时同步执行,需要注意如果algolia过了试用期需要重新登录选一下free套餐,不然搜索不到内容,整体是够用的
3.6 评论系统
评论系统本来想用gitalk,登录不上的时候还折腾了一下用cf的worker自建cors跨域代理api,但最终因为不支持github的private仓库,最后放弃转用valine国际版来配置(需要手机号验证),主要配置照着模板写就行了,参考如下:
[params.page]
rssFullText = false
lightgallery = true
[params.page.comment]
enable = true
[params.page.comment.valine]
enable = true
appId = "xxx"
appKey = "xxx"
placeholder = ""
avatar = "mp"
meta= ""
pageSize = 10
lang = ""
visitor = true
recordIP = true
highlight = true
enableQQ = false
# serverURLs = "https://leancloud.hugoloveit.com"
# emoji 数据文件名称, 默认是 "google.yml"
# ("apple.yml", "google.yml", "facebook.yml", "twitter.yml")
# 位于 "themes/LoveIt/assets/data/emoji/" 目录
# 可以在你的项目下相同路径存放你自己的数据文件:
# "assets/data/emoji/"
emoji = ""需要注意web安全域名,如果支持多站点同步登录需要配置多条域名,另外创建两个对象“Counter”和“Comment”,别的会自动生效,整体免费可用项参考这里,个人博客搓搓有余了,然后评论系统的邮件通知提醒可以参考这个项目,直接在leancloud上使用云引擎运行,测试了一下163和QQ邮箱都可以按预期执行
另外如果涉及到leancloud的流量控制,可以参考这篇文章,
使用github action/各大厂商云函数/cloudflare worker脚本定时访问来避免leancloud休眠
3.7 视频播放
hugo对视频支持也还算可以,不过放不了本地视频,经过一番搜索,我开始准备直接用gif,但是实测后发现gif不仅没声音而且不能暂停,相同内容比mp4体积还大很多,体验不是很好,
后面找到三种关于本地视频播放的教程,第一种是来自:
https://blog.233so.com/2020/04/hugo-loveit-with-dplayer-supported/
https://blog.233so.com/2020/04/hugo-loveit-with-more-video-share-shortcodes-supported/
这位大神直接硬改loveit主题的源代码插入了dplayer的播放器支持,另外还有支持多种网站视频加载,第二种是来自:
比之前简单一点但还是需要引入一堆资源,第三种是学习了以下信息得到,
https://github.com/gevhaz/hugo-theme-notrack/search?q=video-shortcode
在根目录创建layouts\shortcodes\html-video.html,写入:
<style>
.video-shortcode {
width: 100%;
height: auto;
padding: 1em 0;
}
</style>
<video class="video-shortcode" poster="{{ .Get "poster" }}" {{ if ne (.Get "controls") "false" }}controls {{ end }}preload="none" {{ if eq (.Get "autoplay") "true" }}autoplay {{ end }}{{ if eq (.Get "loop") "true" }}loop {{ end }}{{ if eq (.Get "muted") "true" }}muted {{ end }}playsinline>
<source src="{{ .Get "src" }}" type="{{ .Get "type" }}">
There should have been a video here but your browser does not seem
to support it.
</video>然后在博客中直接使用<html-video src="https://xxxx.mp4" poster="xxx.jpg" type="video/mp4">,视频来自第一篇教程那个大神的博客,整体效果如下:
另外最后第一个大神的方案我也简化实现了,全部代码就放一个html,根目录创建layouts\shortcodes\video.html,代码如下:
<style>
.dplayer {
position: relative;
width: 100%;
height: auto;
margin: 3% auto;
text-align: center;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest/dist/hls.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/flv.js@latest/dist/flv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dplayer@latest/dist/DPlayer.min.js"></script>
<div id="{{ .Get `id` }}"></div>
<script>
function loadDPlayer(){
let dp = new DPlayer({
container: document.getElementById({{ .Get `id` }}),
autoplay: {{ .Get `autoplay` | default false }},
theme: {{ .Get `theme` | default `#b7daff` }},
loop: {{ .Get `loop` | default false }},
lang: {{ .Get `lang` | default `zh-cn` }},
screenshot: {{ .Get `screenshot` | default true }},
hotkey: {{ .Get `hotkey` | default true }},
preload: {{ .Get `preload` | default `none` }},
logo: {{ .Get `logo` }},
volume: {{ .Get `volume` | default 0.7 }},
mutex: {{ .Get `mutex` | default true }},
video: {
url: {{ .Get `url` }},
pic: {{ .Get `pic` }},
thumbnails: {{ .Get `thumbnails` }},
type: {{ .Get `type` | default `auto` }},
},
subtitle: {
url: {{ .Get `sub` }},
type: {{ .Get `subtype` | default `webvtt` }},
fontSize: {{ .Get `fontsize` | default `20px` }},
bottom: {{ .Get `bottom` | default `10%` }},
color: {{ .Get `color` | default `#b7daff` }},
},
});
}
document.addEventListener('DOMContentLoaded', loadDPlayer, !1);
</script>dplay的这个难度在于要支持cors,调用方式<video id="highline" url="http://xxx.mp4" pic="xxxxx.jpg">,整体效果相当不错,放个clappr的视频http://clappr.io/highline.mp4纪念一下研究了好久最终没有用的第二个方案吧。。。
dplay一般涉及的参数如下:
| 参数名 | 默认值 | 描述 |
|---|---|---|
| id | 必须 | 播放器父元素唯一 id,用于处理同页面多个播放器,同页面不可重复 |
| url | 必须 | 视频直链地址 |
| pic | 可选 | 视频封面图片 |
| thumbnails | 可选 | 视频缩略图,可以使用 DPlayer-thumbnails 生成 |
| type | 可选,“auto” | 流媒体类型,可选值: ‘auto’, ‘hls’, ‘flv’, ‘dash’, ‘webtorrent’, ‘normal’ 或其他自定义类型, 见#MSE 支持 |
| autoplay | 可选,false | 视频自动播放 |
| theme | 可选,"#b7daff” | 主题色 |
| loop | 可选,false | 视频循环播放 |
| lang | 可选,“zh-cn” | 播放器显示语言,可选值: ‘en’, ‘zh-cn’, ‘zh-tw’ |
| screenshot | 可选,true | 开启截图,如果开启,视频和视频封面需要允许跨域 |
| hotkey | 可选,true | 开启热键,支持快进、快退、音量控制、播放暂停 |
| preload | 可选,“metadata” | 视频预加载,可选值: ‘none’, ‘metadata’, ‘auto’ |
| logo | 可选 | 在左上角展示一个 logo,你可以通过 CSS 调整它的大小和位置 |
| volume | 可选,0.7 | 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效 |
| mutex | 可选,true | 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器 |
| sub | 可选 | 字幕链接 |
| subtype | 可选,“webvtt” | 字幕类型,可选值: ‘webvtt’, ‘ass’,目前只支持 webvtt |
| fontsize | 可选,“20px” | 字幕字号 |
| bottom | 可选,“10%” | 字幕距离播放器底部的距离,取值形如: ‘10px’ ‘10%’ |
| color | 可选,"#b7daff” | 字幕颜色 |
视频这一部分足足花了四五天的时间来进行试错选型和debug优化等工作,第一个bug是我的下载器Neat Download Manager下载的js文件不全导致第一次前几个依赖js的方案全部起不来,第二个bug特别奇怪是cf的缓存导致本地mp4视频在safari上播放不起来,最后参考了这个讨论里面的方案改成自建网盘url链接并修改了nginx的配置使用cf反代网盘文件,第三个bug是dplay要启用cors,
解决第二个bug的时候尝试了自建网盘出链接引发了第三个bug……最后试用了多个基于cf反代的商业网盘并精挑细选了一个方案才最终解决所有bug,生产方案是来自这个项目,就是配置真的是异常复杂,而且代码还有bug默认不支持cors。。。找了好久学习了官方样例才解决cors的问题,
这一部分真是非常不容易,虽然这样的实现还是需要有个vps来自建网盘,并不是原先预计的全serverless博客这种调用url的实现方式需要自建vps或者用某个网盘直链或者反代网盘,都有一定的门槛和技术难度,花了好久才勉强维持serverless博客的初衷,唯一的限制是cf的worker有调用量限制,不过正常一般都是够用的,要是哪天不够用我这blog应该已经非常火了。。。那就到时候买一个付费的worker续上就行,另外记得进行cf的防盗链设置有助于缓解调用量的问题
mp4上传播放就行了,注意大小不要超过25M