记一次博客公式渲染排查

Hexo博客公式非常容易踩的两个坑:一个是公式美元符号与公式之间存在空格,里另一个是不符合KaTeX语法。

而且这两个问题在Typora下是完全看不出来的。

我的数据库博客就有很多这样的问题,相当长的一段时间里没有解决。今天抽空搞定了,写点心得。

空格问题

这个其实非常好解决,比如 $ \forall a \in A $

我们只需要将 “$ ” 和 " $"直接进行替换就行(注意带上空格)。同时这种问题在博客中特征是非常明显的,通过浏览器搜索美元符号就能排查。

KateX渲染问题

这个要麻烦一些,因为并没有明显特征,只能遍历博客检查。

由于我通常喜欢用LaTeX写,但Hexo渲染实际上用的是KaTeX,但Typora里也看不出来KateX下有没有问题

我遇到的暂时是这两个情况

  • 与或非:,,¬\wedge ,\vee,\lnot,\wedge ,\vee,\lnot与\and ,\or, \not,后者就会出现渲染问题
  • \overset,这个我也没太细究怎么解决,直接放图片了事

 

Hexo公式对括号嵌套的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
      at formatNunjucksError (your blog path\node_modules\hexo\lib\extend\tag.js:171:13)
at your blog path\node_modules\hexo\lib\extend\tag.js:246:36
at tryCatcher (your blog path\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (your blog path\node_modules\bluebird\js\release\promise.js:547:31)
at Promise._settlePromise (your blog path\node_modules\bluebird\js\release\promise.js:604:18)
at Promise._settlePromise0 (your blog path\node_modules\bluebird\js\release\promise.js:649:10)
at Promise._settlePromises (your blog path\node_modules\bluebird\js\release\promise.js:725:18)
at _drainQueueStep (your blog path\node_modules\bluebird\js\release\async.js:93:12)
at _drainQueue (your blog path\node_modules\bluebird\js\release\async.js:86:9)
at Async._drainQueues (your blog path\node_modules\bluebird\js\release\async.js:102:5)
at Async.drainQueues [as _onImmediate] (your blog path\node_modules\bluebird\js\release\async.js:15:14)
at process.processImmediate (node:internal/timers:478:21) {
line: 1497,
location: '\x1B[35m_posts/xxxxxx.md\x1B[39m [Line 1497, Column 6644]',
type: 'expected variable end'
}
} Something's wrong. Maybe you can find the solution here: %s https://hexo.io/docs/troubleshooting.html

出现上述原因都是因为你的Markdown文件中有标签与nunjucks模板引擎的标签冲突了,比如{{}}`,`{#`, `{%`,这些标签都是模板引擎的,如果Markdown文件中有这些标签,那么在解析的是就会把Markdown中的标签动态解析了。通常情况下是不允许的。 有关模板引擎nunjucks更多相关信息请转到[https://mozilla.github.io/nunjucks/cn/getting-started.html](https://mozilla.github.io/nunjucks/cn/getting-started.html) 在hoxe的官网上有很多[相关的提问](https://github.com/hexojs/hexo/issues?utf8=%E2%9C%93&q=unexpected+token),上面也提供了解决方案(本文的方案1),但是都不太好。 特别是你执行`hexo g`命令的时候就会提示Markdown文件解析错误。 网上很多方法都是使用如下标签处理。

1
2
3
{% raw %}
{{name}}
{% endraw %}
但是治标不治本啊,如果是用这个标签处理,那么你后续的Markdown文件内容但凡是包含`{{}}或者{{#}}等等这些标签的内容都会解析失败,那么有什么好的处理方案呢?

答案是有的,我们可以直接修改nunjucks模板的源代码,找到如下文件:

1
node_modules/nunjucks/src/lexer.js

在文件的开头可以看到如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
'use strict';

var lib = require('./lib');

var whitespaceChars = " \n\t\r\xA0";
var delimChars = '()[]{}%*-+~/#,:|.<>=!';
var intChars = '0123456789';
var BLOCK_START = '{%';
var BLOCK_END = '%}';
var VARIABLE_START = '{$';
var VARIABLE_END = '$}';
var COMMENT_START = '{@';
var COMMENT_END = '@}';
var TOKEN_STRING = 'string';

可以直接改了这些渲染标签,比如我的Markdown文件中就是需要显示{{name}}这一类代码。那么你可以这么做:

1
2
var VARIABLE_START = '{$';
var VARIABLE_END = '$}';

把模板引擎的占位符修改为其他字符之后,这样模板解析的时候就不会跟你的Markdown内容冲突了,而且是对所有Markdown文件都有效的。

但是需要注意的时候,如果你在项目下执行npm install更新nunjucks模板,那么你修改的node_modules/nunjucks/src/lexer.js会被还原,需要重新修改一遍

搜索、RSS插件同步修改

如果你的博客使用hexo-generator-feed或者hexo-generator-search或者是其他依赖于hexo的插件,那么你也需要同步修改这些插件的模板处理标签。
比如hexo-generator-search这个插件,通常是用于搜索,比如本站的搜索功能,这些插件也是依赖于nunjucks模板的,所以你也要修改他们的源代码,一搜索插件为例:

修改如下文件的标签:

1
node_modules/hexo-generator-search/templates/search.xml

把文件内容里的{改为{$即可,这个修改是根据你前面的nunjucks修改而定的。

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
<?xml version="1.0" encoding="utf-8"?>
<search>
{% if posts %}
{% for post in posts.toArray() %}
<entry>
<title>{$ post.title $}</title>
<link href="{$ (url + post.path) | uriencode $}"/>
<url>{$ (url + post.path) | uriencode $}</url>
<content type="html"><![CDATA[{$ post.content | noControlChars | safe $}]]></content>
{% if post.categories and post.categories.length>0 %}
<categories>
{% for cate in post.categories.toArray() %}
<category> {$ cate.name $} </category>
{% endfor %}
</categories>
{% endif %}
{% if post.tags and post.tags.length>0 %}
<tags>
{% for tag in post.tags.toArray() %}
<tag> {$ tag.name $} </tag>
{% endfor %}
</tags>
{% endif %}
</entry>
{% endfor %}
{% endif %}
{% if pages %}
{% for page in pages.toArray() %}
<entry>
<title>{$ page.title $}</title>
<link href="{$ (url + page.path) | uriencode $}"/>
<url>{$ (url + page.path) | uriencode $}</url>
<content type="html"><![CDATA[{$ page.content | noControlChars | safe $}]]></content>
</entry>
{% endfor %}
{% endif %}
</search>

其他插件处理方法类似,找到模板解析标签全局修改即可。

该解决方案摘自 : https://xcoding.tech

一些调试Tips

推荐使用 hexo g && hexo s预览,修改后直接刷新页面就可以看到改的效果,还是很方便的