博客主题更新到 Next 顺便记录过程遇到的一些问题

博客还是用的 Hexo, 太久没更新文章了, 今天新增了一篇关于 Vue 的文章后, 直接 generate 然后上传, 结果上传之后才发现所有生成的文件全部都是 0 字节的空文件, 也找不到原因.

最新版 Hexo 已经是 5.x 距离我用的 3.8 更新了两个大版本, 同时原来用的主题也不再维护了, 这么去找问题原因还不如重新整一个了, 于是开始折腾不知不觉弄了一晚上.

得益于 Hexo 的特性, 文章的迁移仅仅是从一个文件夹拷贝到另一个文件夹这么简单, 基本上所有时间都花在了找模板还有模板的功能配置上, 中途遇到了好几个问题, 幸运的是最终都解决了.

Next 这个主题功能还是比较强大, 博客左侧的搜索功能完美解决了全局搜索的需求, 非常方便, 非常欢迎各位体验, 也希望我的博客能帮助到大家.

目前博客的访问量和评论数据暂时未迁移, 因为用到的服务不同无法通用, 这些数据可能不再保留.

所有资源也和博客内容进行分离, 方便管理和维护.

下面记录一下更新过程的一些注意事项或者说明:

配置文件

所有主题相关配置文件都在 _config.next.yml 里面写, 官方文档: https://theme-next.js.org/docs/getting-started/

配置文件说明:
Configuration | NexT
Configuration | Hexo

文章页也会显示摘录(excerpt)的问题

我的大部分文章 <!-- more --> 前面都是摘自文章头部部分内容, 打开文章页会显示摘录和内容, 这样内容就重复了, 自然不能忍, 于是从模板开始一路找, 主题和 Hexo 官方 Git 仓库还有百度 Google 都没找到支持配置修改的, 最后只得自己动手, 发现是 Hexo 原生渲染的 page.content 内容就包含了开头的摘录, 所以只能利用官方提供的 filter 功能来修改内容了. 新建文件 scripts/filter.js 写上如下代码:

1
2
3
4
5
const regex = /[\s\S]*?<(?:span|a) id="more"><\/(?:span|a)>/
hexo.extend.filter.register('after_post_render', function (data) {
data.content = data.content.replace(regex, '')
return data
})

Hexo v5.4.0 的更新中,有一个 breking change 将渲染后的 excerpt anchor 由 a 改成了 span ,见 #4627,所以为了尽可能兼容,于 2021-06-12 更新了上述脚本同时支持 Hexo v5.4.0 之前和之后的版本。

完美搞定.

站点地图 (sitemap.xml)

插件不提供这个功能, 还是和原来博客一样用这两个插件:

HTML 压缩

为了尽可能减少体积, 折腾了一下 HTML 压缩功能, 所有全站输出的资源没用的空白字符等都被删除了, 效果如下图:

这里用到了 html-minifier, 过程还出现了各种报错, 比如因为 Next 主题里面有 ECMAScript 或更高的 JavaScript 代码, 导致 UglifyJS 报错, 需要用到 Babel 转换一下, UglifyJS 也有提到: “To minify ECMAScript 2015 or above, you may need to transpile using tools like Babel.”.

所以经过各种调试踩坑, 实现 HTML 压缩的步骤大概如下:

  1. 引入依赖库

    1
    2
    3
    $ yarn add @babel/core @babel/preset-env html-minifier
    # 或者你用的是 npm:
    npm install @babel/core @babel/preset-env html-minifier
  2. scripts 目录下面的任意 js 文件内添加如下代码(我这里加到了上面提到的 js 文件 scripts/filter.js 中):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    hexo.extend.filter.register('after_render:html', function (str, data) {
    return minify(str, {
    collapseWhitespace: true,
    removeComments: true,
    minifyCSS: true,
    minifyJS: text => {
    text = text.trim()
    if (text) {
    const js = babel.transform(text, { presets: ['@babel/env'] })
    const result = UglifyJS.minify(js.code)
    return result.code
    } else {
    return ''
    }
    }
    })
    })

然后重新运行 server 或者 generate 即可看到效果.

按道理是可以控制仅在 generate 生成时进行 HTML 压缩, 方便 server 时调试, 这里暂时没需求就不写这个判断代码了, 需要时注释掉上面的代码即可.