我是一名前端开发人员,因此对其他的一些脚本语言如 Ruby 并不熟悉。刚开始写博客的时候使用了 Github Pages 作为博客平台,它默认使用的是 Jeklly 框架,想着内容比框架更重要,因此也就用着了,这一用就是 10 年。
期间换过一些主题,后来锁定了 Hux 提供的主题,简洁大方好看,而且是开源的:
我针对这个主题做了很多的定制化内容,如自定义右侧内容、自定义数据、使用 Notion 作为数据源渲染等。
但随着苹果的 M 系列芯片的发布,我越来越难以处理 Ruby 在 Intel 和 Apple 芯片之间的差异,举个例子来说,我构建的时候需要特定使用 x86 架构的指令才能偶然正确 build,这还是我不能随便动任意一个依赖的前提下:
arch -x86_64 bundle exec jekyll server --trace --config=_config.dev.yml --ssl-key local.xheldon.cn.key --ssl-cert local.xheldon.cn.pem
因此我意识到如果再不尽快更换框架,我可能将来就完全无法发布博客了。
这一节没有什么好说的,你基本可以认为,Hexo 是 Jekyll 的 JavaScript 实现。里面的很多概念,95% 的都相同,因此迁移上手无难度。
更重要的是,Hexo 中也有人做了 Hux 的博客主题模板,因此我就直接拿来用了,在这个过程中简单记录一下过程。
这个属于比较容易的,在 Jekyll 中的插件,在 Hexo 中我是用辅助函数实现,如下是我处理来自 Notion 的 Bookmark 的标签的函数(路径是 _plugins/add-attribute.rb
:)
module Jekyll
class RenderBookMarkBlock < Liquid::Block
def initialize(tag_name, attr, tokens)
super
# 普通的链接没有 yid 和 bid
attrs = attr.scan(/url\\=\\"(.*)\\"\\stitle\\=\\"(.*)\\"\\simg\\=\\"(.*)\\"\\syid\\=\\"(.*)\\"\\sbid\\=\\"(.*)\\"/)
if !attrs.empty?
@url = attrs[0][0]
@title = attrs[0][1]
@img = attrs[0][2]
@yid = attrs[0][3]
@bid = attrs[0][4]
@firstChar = @title.empty? ? "" : (@title)[0].upcase
@error = ""
else
attrs = attr.scan(/url\\=\\"(.*)\\"\\stitle\\=\\"(.*)\\"\\simg\\=\\"(.*)\\"/)
@url = attrs[0][0]
@title = attrs[0][1]
@img = attrs[0][2]
@firstChar = @title.empty? ? "" : (@title)[0].upcase
@error = ""
end
end
def render(context)
@desc = super
if [email protected]? && [email protected]?
"<p class='embed-responsive embed-responsive-16by9'><iframe src='<https://www.youtube.com/embed/#{@yid}?rel=0>' title='YouTube video player' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen></iframe></p>"
elsif [email protected]? && [email protected]?
"<p class='embed-responsive embed-responsive-16by9' style='border-bottom: 1px solid #ddd;'><iframe src='//player.bilibili.com/player.html?bvid=#{@bid}&high_quality=1&as_wide=1' scrolling='no' border='0' frameborder='no' framespacing='0' allowfullscreen></iframe></p>"
else
"<p><a class='link-bookmark' href='#{@url}' target='_blank'><span data-bookmark-img='#{@img}' data-bookmark-title='#{@firstChar}'><img src='#{@img}'/></span><span><span>#{@title}</span><span>#{@desc}</span><span>#{@url}</span></span></a></p>"
end
end
end
end
Liquid::Template.register_tag('render_bookmark', Jekyll::RenderBookMarkBlock)
而在 Hexo 中我是这么写的(路径是 scripts/liquid.js
):
hexo.extend.tag.register('render_bookmark', function(args, content) {
const [url, title, img, yid, bid] = args.map(getValue);
const firstChar = title ? title[0].toUpperCase() : '';
const strip_html = hexo.extend.helper.get('strip_html').bind(hexo);
const trim = hexo.extend.helper.get('trim').bind(hexo);
if (yid) {
return `<p class='embed-responsive embed-responsive-16by9'><iframe src='<https://www.youtube.com/embed/${yid}?rel=0>' title='YouTube video player' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen></iframe></p>`
} else if (bid) {
return `<p class='embed-responsive embed-responsive-16by9' style='border-bottom: 1px solid #ddd;'><iframe src='//player.bilibili.com/player.html?bvid=${bid}&high_quality=1&as_wide=1' scrolling='no' border='0' frameborder='no' framespacing='0' allowfullscreen></iframe></p>`;
}
return `<p><a class='link-bookmark' href='${url}' target='_blank'><span data-bookmark-img='${img}' data-bookmark-title='${firstChar}'><img src='${img}'/></span><span><span> ${title}</span><span> ${strip_html(trim(content))}</span><span> ${url}</span></span></a></p>`;
}, {
ends: true,
});
不知道为什么,我在 Hexo 中设置了 :category/:name.html
但是依然给我生成的是 life/2024-life-xxx.html
(使用 -
目录分割) 而预期应该是 life/xxx.html
,看源码 name
使用了 slug
,的 basename
,但是 slug
生成逻辑是基于 folder 路径然后加上 - 的,因此我只能自己手动修改文件名。Jekyll 中,文件名前的日期格式,如 2024-02-12-xxx.md 中,2024-02-12 会被忽略,title 直接就是 xxx,但是在 Hexo 中 title 在 post 中读取的 title front matter,所以只能写一个 filter 插件来最终确定 permalink 地址:
/**
* permalink 中的 name 不符合预期,对于 _posts/life/2015/xxx.md 来说,在文档中 :name 表示的是 xxx,但是实际是 life-2015-xxx
*/
hexo.extend.filter.register('post_permalink', function (data) {
// 在这里修改 post.name 的值
const arr = data.split('/').filter(Boolean);
const categories = arr[0];
const name = arr[1];
return `${categories}/${name.split('-').filter(Boolean).slice(3).join('-')}`;
});