前两天,我出于某种原因升级了本地的node.js。然后我就发现我的博客没法用了,网址打开是一片乱码。经过查询确认,我发现原来是因为hexo不支持高版本的node.js。当时我就折腾了半天版本上的事情。并且升级完之后,还不得不使用新版的next主题。新版主题不支持valine评论系统,所以我不久之前好不容易搞明白的评论系统就又没用了。经此一事,我觉得或许有必要对于自己的网站有更深的理解。

本文中的版本

  • hexo 5.4.2
  • hexo-cli 4.3.0
  • NexT 8.11.1

更新 NexT 主题

更新了 Next 主题。看起来,它的 repo 位置有过几次改变,因此我的升级过程走了一些弯路。不过,这里提供了有用的知识。先不考虑自定义的那些东西,只是把它装上。我留了旧版的 next,然后把新版另起了一个文件夹。

1
git clone https://github.com/next-theme/hexo-theme-next themes/next-reload  

这样,还要在根目录的_config.yml里面改变 theme 为 theme: next-reload

NexT 主题的美化

以前,我习惯于把 next 主题的个性化设置直接写在themes/next/_config.yml里面,但是这隐含着一种悲观的预期,也就是说,我随时都要准备跑路,也觉得 next 这个主题也随时都要跑路,所以我才为了省事而假装我永远不需要更新 next,而一旦更新,我还需要手动把设置都弄回去。上次,我就忘了这回事,结果把个性化设置弄丢了,还要重新弄一遍。

所以这次我参考了官方文档的说法,把 theme config 拉出来放在 hexo config 里面了。具体做法就是在根目录的_config.yml里面加入你想改变的个性化设置:

1
2
3
4
5
6
7
8
9
# Next theme config:  
theme_config:  
  # Schemes  
  scheme: Pisces  

  # thumbnail  
  favicon:  
    small: (place where you put the images)  
    other configs...  

设置自己的缩略图

一般来讲,浏览器里显示的网页标签包含标题和缩略图两部分。使用 next 主题时,默认的缩略图是 next 主题的标志,一个六边形加字母 N,令人想到那不勒斯的队徽,十分的晦气。因此我画了一个橘子替代它。在根目录新建一个source\images文件夹,把图片放进去,然后在个性化设置的favicon一栏指向这些图片。
另外,在themes\next-reload\source\css\_variables\Pisces.styl里面调

1
$site-author-image-border-width = 0px;  

去掉烦人的边框。

配置 next 主题自带的搜索功能

需要安装一个插件

1
npm i hexo-generator-searchdb  

_config.yml里面加上

1
2
3
4
5
search:  
path: search.xml  
field: post  
content: true  
format: html  

并且在 next theme config 里面打开local_search

更改字体

以前用的是黑体。但是最近感觉阅读汉字需要衬线的帮助了,所以决定换成 Noto Serif。在_config.yml里面更改字体设置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
font:  
    enable: true  

    # Uri of fonts host, e.g. https://fonts.googleapis.com (Default).  
    # host:  
    # can use loli.net in case  
    host: https://fonts.loli.net  

    # Font options:  
    # `external: true` will load this font family from `host` above.  
    # `family: Times New Roman`. Without any quotes.  
    # `size: x.x`. Use `em` as unit. Default: 1 (16px)  

    # Global font settings used for all elements inside <body>.  
    global:  
      external: true  
      family: Noto Serif SC  
      size:  

    # Font settings for site title (.site-title).  
    title:  
      external: true  
      family: Noto Serif SC  
      size:  

    # Font settings for headlines (<h1> to <h6>).  
    headings:  
      external: true  
      family:  
      size:  

    # Font settings for posts (.post-body).  
    posts:  
      external: true  
      family: Noto Serif SC  

    # Font settings for <code> and code blocks.  
    codes:  
      external: true  
      family: Source Code Pro  

此外,还希望标题弄成稍微粗一点的字体。找了一下,在\themes\next-reload\source\css\_common\components\post\post-header.styl里面的posts-expand .post-title那里,加入

1
font-weight: bolder;  

就可以了。

其他

  • 侧边栏加入阅读进度百分比:
    scrollpercent: true

  • 页脚删除“由 Hexo & NexT.xxx_theme 强力驱动”,换成自定义内容:

    1
    2
    3
    4
    
    # If not defined, `author` from Hexo `_config.yml` will be used.  
    copyright: 自定义内容  
    # Powered by Hexo & NexT  
    powered: false  
    
  • 设置书签功能:bookmark

  • 默认目录展开:在_config.ymltoc(table of content)中打开expand_all

  • 添加字数和阅读时间统计:
    安装一个插件

    1
    2
    
    npm i hexo-word-counter --save  
    hexo clean  
    

    并打开wordcount。

  • 把某些地方刷橙:在\themes\next-reload\source\css\_variables\base.styl里面可调。

KaTeX

出于一些原因,还要重装 hexo。每次重装之后,都要调整一些 markdown 渲染的问题,其中最重要的就是公式。以前,我使用 mathjax,但是这回试了一下 katex。看起来后者要快一些。

KaTeX是可汗学院搞出来的一个 JS 库,和 mathjax 一样,用来在网页上显示 LaTeX 排版的东西。感觉原理上,mathjax 输出的是 html 文档,要把 hexo 渲染出来的 html 再渲染一遍。而 katex 是从 tex 代码生成 html 片段,所以比较快。

安装 KaTeX

去掉了自带的渲染器,装上新的

1
2
npm un hexo-renderer-marked --save  
npm i @upupming/hexo-renderer-markdown-it-plus --save  

在根目录的_config.yml最后加上

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Markdown config:  
markdown:  
  render:  
    html: true  
    xhtmlOut: false  
    breaks: true  
    linkify: true  
    typographer: true  
  plugins:   
  anchors:  
    level: 2  
    collisionSuffix: 'v'  
    permalink: true  
    permalinkClass: header-anchor  
    permalinkSide: 'left'  
    permalinkSymbol: 

这里面好像 plugins 不加 markdown-it-katex 也没事,是默认 enable 的。这个渲染器可以弄很多插件,比如 emoji,footnote什么的,不过我暂时并不需要。

$\KaTeX$ 和一般的 $\LaTeX$ 在我的使用范围内没有什么区别。有的东西太久不用也会忘,有一个 cheatsheet

另外,这个方案下,在$的内部最好没有空格,否则会报警(LaTeX-incompatible input and strict mode is set to 'warn': Unicode text character used in math mode)。公式内换行用\\看起来没啥问题,但是最好留意一下。

KaTeX 实现引用公式的一种办法

更新 现在这一套又用不了了。。。

前面说,katex 的原理是输入 tex,输出 html片段,所以在这情况下,做公式的自动计数和引用是比较难的,似乎 katex 本身还不支持 \ref ,不过我找到了一个别人的办法,参考了一下。

具体来说,hexo 里面肯定是用某种插件实现 katex 渲染的,我是在装 @upupming\hexo-renderer-markdown-it-plus 之后发现它自带了一个 markdown-it-katex,装在 \node_modules/@abreto下面。进去找到\node_modules\@abreto\markdown-it-katex\index.js,看到

1
2
3
module.exports = function math_plugin(md, options)  
// Default options  
    options = options || { }  

于是把options改成

1
2
3
4
5
6
7
options = options || {  
        trust: (context) => ['\\htmlId', '\\href'].includes(context.command),  
        macros: {  
          "\\eqref": "\\href{###1}{(\\text{#1})}",  
          "\\ref": "\\href{###1}{\\text{#1}}",  
          "\\id": "\\htmlId{#1}{}"  
        }  

这里面原理就是让 katex 信任 htmlId 和 href,这样就可以定义几个宏,手动把公式的编号打上 html id,然后用超链接的形式去索引他们。

在 KaTeX 的宏定义中,可以以#数字的形式设置占位符,按顺序对应定义的参数。如 \test{1}{2}{3} 宏指令的定义若要依次引用第 1、2、3 个参数,就以#1#2#3 占位即可。占位符可重复引用,不同的占位符最多 9 个。
\id 指令用\htmlId 模拟,用于生成页面内锚点,在 LaTeX 中与 \tag 或 \caption 配合使用,所以我们在这里也将 \htmlId 的第二个参数留空,在页面上不做显示。
\ref 和 \eqref 指令都是引用,区别在于后者会加上括号,一般用于公式的引用。我们用 \href 指令来模拟,第一个参数是跳转的链接,第二个指令是引用显示。一般引用显示都是数字或字母的编号,为了避免被 KaTeX 引擎识别为变量,加一个 \text 指令。需要注意的是,由于页面锚点的 URL 也是用#表示,这会引发和宏定义占位符的冲突。所幸 KaTeX 的引擎考虑到了这一点,使用两个#,也就是##就可以表示#本身,而不会被当作占位符解析(其实是我试出来的)。

有一个很烦的事情,我刚弄的时候这个东西一直实现不了,最后发现是 html id 相关的内容在 @abreto\markdown-it-katex\node_modules\katex里面缺失了,所以我就十分粗暴地单独安装了一个 katex,然后把这里面的内容直接替换了,结果就好了。

最后的效果就是这样的:

1
2
3
$$ \text{ 重要的很长的公式 }\id{ 1.1 }\tag{ 1.1 } $$  

所以,我们回忆起$ \eqref{ 1.1 } $或者$ \ref{ 1.1 } $...  

当然,这个时候一定会报

1
LaTeX-incompatible input and strict mode is set to 'warn': HTML extension is disabled on strict mode [htmlExtension]  

一些以前没有发现的功能

markdown 中使用 html 标签(已经设置了 markdown 渲染器中 html: true):

  • 下划线:<u>underlined</u>=underlined
  • 带有颜色的字体:<font color=cyan>colored</font>=colored
  • 高亮:<mark>highlighted</mark>=highlighted
  • 删除线:<del>deleted</del>=deleted
  • 波浪线:<span style="text-decoration-line: underline; text-decoration-style: wavy;">wavy</span>=wavy
  • 双下划线::<span style="text-decoration-line: underline; text-decoration-style: double; ">double underlined </span> =double underlined

hexo 中的标签功能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{% note default 点击展开 %}  # default 是标签的类型  
default 标签中的内容   
  {% note primary 还可以点击展开 %}  
  primary 标签中的内容  
  {% endnote %}  
{% endnote %}   

{% note success 展开 %}  
success  
{% endnote %}  

{% note info 展开 %}  
info   
{% endnote %}  

{% note warning 展开 %}  
warning  
{% endnote %}  

{% note danger 展开 %}  
danger  
{% endnote %}  

一般来说,可以在themes/your_theme/_config.yml里面调整标签的风格。

零敲碎打

  • 对于每一篇历史文章都重新手动确定了 categories/分类 和 tags/标签。
  • 标签页仍然展示文章目录的问题。具体来说,标签页应该只显示一堆分散的标签,不具备文章的结构,因此自然没有在侧边栏展示文章目录的道理。但是,我使用的 Pisces scheme 仍然有这个性质。以前感觉这是一个小问题,这次顺便就给解决了。在\themes\next-reload\layout\_macro\sidebar.njk里面把set display_toc那里改成
    1
    
    {%- set display_toc = page.toc.enable and display_toc and page.type != "tags" %}  
    

    就可以了。