本文主要记录我将 GitHub 的个人博客从 Jekyll 迁移到 Hexo 的一些踩坑实践。
为什么迁移
- Jekyll搭建博客所需的技术栈(如Liquid语言、Ruby、gem等)我不太熟悉,每次想改点啥都不方便;而 Hexo 是基于Node.js的,js相对熟悉一点,定制起来方便一些。
- Hexo 生成站点的速度更快,且该框架是台湾人贡献的,中文文档很多。
网上对比的文章 How to Choose the Right Static Generator: Jekyll vs. Hugo vs. Hexo
Hexo和博客主题
Hexo 简介
Hexo的安装可以参考Hexo官网,需要先安装node.js和git,照着文档安装就行了。
常用指令有:
- 清除缓存:
hexo clean
- 生成静态文件:
hexo generate
,简写hexo g
- 启动服务器:
hexo server
,简写hexo s
- 部署到远程站点:
hexo deploy
,简写hexo d
主题选择
Hexo的主题有很多,可以从下面几篇推荐里挑挑:
我主要有几个需求:
- 支持搜索
- 目录显示当前所处章节:阅读文章时显示目录TOC,且滑动到文章相应位置时,目录同步定位
- 支持赞赏展示和自定义页面
- 支持标签和分类
简单比较了下,选择了indigo
搭建博客
大致以下几个步骤:
- 安装Hexo
- 选用主题,并根据主题的安装步骤去更改配置项
- 本地
hexo clean & hexo g
生成本地文件,hexo s
启动本地服务器,访问http://localhost:4000/
查看效果
可以通读以下博客了解细节:
indigo 主题的wiki: https://github.com/yscoder/hexo-theme-indigo/wiki
我的定制修改
我写了个Java程序把原来Jekyll下博客的md文件copy到了新的文件夹下,并对每个md文件需要适配的地方(如摘要是通过<!-- more -->
来区分的)进行了批量处理。
统计
很多主题都支持访问统计,一般需要在配置文件配置自己对应账号的key,我一般使用Google Analytics+百度统计:
- Google Analytics: https://analytics.google.com/analytics/web/
- 百度统计: https://tongji.baidu.com/web/homepage/index
其中有官方提供的统计js代码,indigo的代码有些过时了,可通过配置文件里统计配置对应的关键字全局搜索,找到对应代码,并更新成最新的js。
具体地,indigo主题的统计代码在themes/indigo/layout/_partial/plugins
目录下的baidu.ejs
和google-analytics.ejs
,其他主题也可通过类似方法修改
搜索
针对无数据库的静态博客搜索方案一般有两种:
- 第三方搜索服务;
- 序列化站点内容作为数据源,然后自己写查询方法。
indigo作者是通过自定义搜索实现的,搜索方案为:Hexo添加站内搜索功能初步完成。原理比较简单,简单概括就是:
先通过hexo-generator-json-content
插件生成json格式的数据文件,然后将这个数据文件作为数据源,对输入进行正则匹配。由于我只需要简单搜索,简单正则就能满足我的要求,该方案基本可以,所有没有增加分词等高级搜索的功能。
但有他的实现有几个问题:
- 没有对输入转义,直接根据输入生成正则,当输入包含正则元字符时前端会报错,且把空格替换为了
或
的逻辑,而不是且
的逻辑 - 没有权重,标题、正文等只要出现关键字就显示,导致我很多文章都有git地址,只要输入git,全匹配了,没有区分度
- 没有对摘要进行搜索
所以我做了简单的修改:
- 转义用户输入中的正则元字符
- 生成json数据文件时增加摘要字段,去掉正文字段,以减少json文件大小(可选,也可以不去掉)
- 增加权重,权重大小:标题>摘要>标签>正文
修改themes/indigo/source/js/search.js
即可在本地测试,发布线上的话,需要mimify js文件,然后替换掉原来的themes/indigo/source/js/search.min.js
,压缩js的工具网站:https://javascript-minifier.com/
以下是具体实现,没兴趣可略过
修改前后的正则(注释的为修改前的):
1 | // var regExp = new RegExp(key.replace(/[ ]/g, '|'), 'gmi'); |
其中function escapeRegExp(string)
参考正则escape:
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
- https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
同时,匹配结果不再只返回true/false
,而是返回权重,搜索结果更根据权重排序:
1 | // 匹配文章内容返回结果,返回值代表权重。按照标题,摘要,标签,正文的顺序递减 |
归档样式
indigo主题默认archives(归档)的样式有两点不满足我的偏好:
- 默认的卡片样式太占地方,一个分页放不下几篇博客名。归档我想尽可能多的按时间降序排列展示博客列表,而默认的归档样式,和categories(分类)以及tags(标签)的样式一样,使用了卡片作为列表项,不太喜欢。
- 时间按月划分而非按年划分。我希望以年为粒度来归档
涉及的文件/用途:
themes/indigo/layout/archive.ejs
: 归档页面主体内容对应的文件,类似HTML模板的作用themes/indigo/layout/_partial/archive.ejs
: 列表项的展示内容,类似可复用的HTML公共模板themes/indigo/source/css/_partial/archives.less
: 归档页面的对应样式themes/indigo/source/js/main.js
: 原列表项的瀑布流是每行两列的,一些展示逻辑例如每一项(.waterfall-item
)的元素位置高度在该文件计算和补充
我的修改:
- 修改归档时间粒度:将
themes/indigo/layout/archive.ejs
文件内的“by年月”分组的逻辑改为按年分组。同时,列表项的时间格式改为自己喜欢的MM-DD
- 修改每个列表项的展示内容
- 上述
archive.ejs
文件使用了 hexo 的partial
辅助函数引用了themes/indigo/layout/_partial/archive
文件,但由于该文件被categories(分类)以及tags(标签)页面共用了,所以不要直接修改,而是在同目录(_partial
)下新建自己的归档文件my-archive
并修改引用 - 在
my-archive
文件定制自己喜欢的列表展示信息,可借鉴参考原来的写法。并在themes/indigo/source/css/_partial/archives.less
定制CSS样式,建议添加新className(例如.archive-item
)而非直接在原样式上修改 - 原列表项样式
.waterfall-item
的渲染逻辑涉及到了themes/indigo/source/js/main.js
文件,仿照其写法补充自定义列表项(.archive-item
)的元素位置高度
- 上述
- bugfix: 修改原博客列表项的日期格式
config.date_format
->date_format
,(位于文件themes/indigo/layout/_partial/post/date.ejs
),否则引用它的文件传入的日期格式没法生效
main.js
的补充代码如下(原.waterfall-item
的渲染是两列,归档.archive-item
的渲染改为一列)
1 | // 自定义的归档 |
和前面的“搜索”定制一样,修改themes/indigo/source/js/main.js
即可在本地测试,发布线上的话,需要mimify js文件,然后替换掉原来的themes/indigo/source/js/main.min.js
,压缩js的工具网站:https://javascript-minifier.com/
遇到的问题
安装hexo失败
- 报错:
Missing write access to /usr/local/lib/node_modules/hexo-cli
- 解决: 进入文件夹
/usr/local/lib
,修改权限
1 | $ cd /usr/local/lib where the global node_module folder is found |
自定义域名
- 问题:绑定失败
- 解决:
- 申请并购买一个自定义域名
- ping你的github.io域名,得到一个IP
- 在你的域名的 DNS 配置中添加A类型的记录,主机记录为
@
,记录值为上述IP - 在仓库根目录添加
CNAME
文件,并在文件中填写绑定的顶级域名 - 在对应仓库的设置里
Settings->GitHub Pages->Custom domain
写上你的自定义域名 - 有的博客说还要更换DNS服务器地址为
f1g1ns1.dnspod.net
和f1g1ns2.dnspod.net
,我没换也成功了。
- 参考
由于自定义域名后原来的统计数据就从零重计了,所以就放弃了,还是使用github.io的域名算了。
清理DNS缓存
- 问题:配置自定义域名失败,一直跳空白或者找不到地址,删除DNS解析配置也没用
- 解决:需要清除本地DNS缓存以及chrome缓存
1 | sudo killall -HUP mDNSResponder; sleep 2; |
chrome缓存清理:设置->高级->隐私设置和安全性->清除浏览数据
或者右上角三个点->更多工具->清除浏览数据
- 参考:
博客原文的备份
- 问题:使用Hexo后,仓库只有生成的public文件夹下的文件,博客都是html,原来的博客原文没有版本管理
- 解决:新建分支
hexo-public
(名字自取),将hexo的根目录作为仓库根目录,这样发布的内容在master
分支,而编辑的内容和各种配置等原始信息在hexo-public
实现版本管理- 使用的主题的对应文件夹下会包含
.git
,git add
时会有一些提示,根据自己需要删除.git
,或者作为子模块进行管理。最好不要直接git rm --cached
,否则后续对主题的修改不会被追踪
- 使用的主题的对应文件夹下会包含
- 参考: