经过一周多陆陆续续的折腾,到现在本博客基本实现了博客 Markdown 渲染和 Typora, VSCode 等的默认预览中数学公式的表现一致。
Note: 大于号(
>)小于号(<)目前没有做额外的转义(它们本身是 HTML 标签的结束和开始),但是这个用\lt和\gt就行了,所以有点懒得改。如果要改的话,就对
math的处理加上这两个东西的 escape 就好,MathJaX 本身会识别出<和>的。
简单来说,我分别魔改了 marked 和 hexo-renderer-marked 两个包,实现了内联 LaTeX 的正确 Tokenize 和 Renderer (i.e. 什么也不做,原样输出),再由浏览器里运行的 MathJaX 3 来进行 LaTeX 渲染。
魔改后的版本支持块公式 (block math) $$ ... $$ 和内联公式 (inline math) $ ... $,并且内联公式内部的 _ 不会和 Markdown 对 _ 的使用冲突。
下面是渲染 Maxwell 方程组的示例:
$$ \begin{aligned} \nabla \cdot \mathbf{E} &= \frac {\rho} {\varepsilon_0} \\ \nabla \cdot \mathbf{B} &= 0 \\ \nabla \times \mathbf{E} &= -\frac{\partial \mathbf{B}} {\partial t} \\ \nabla \times \mathbf{B} &= \mu_0\left(\mathbf{J} + \varepsilon_0 \frac{\partial \mathbf{E}} {\partial t} \right) \end{aligned} $$上面的 $ \mathbf{E} $ 是电场强度,$ \mathbf{B} $ 是磁感应强度,$ \mu_0$ 是真空磁导率,$ \epsilon_0 $ 是真空介电系数。
marked是hexo-renderer-marked使用的 Markdown 渲染器,它负责把 Markdown 渲染成 HTML。
为什么要新造一个轮子?
Google 一圈,现在有的 Hexo 内联 LaTeX 的方案都不是很让人满意:
hexo-renderer-kramed使用的kramed从 2016 年开始已经没有再更新了marked表示不会加入对$ ... $和$$ ... $$的支持 (markedjs/marked, Issue #722)hexo-renderer-pandoc需要用户自己安装pandoc,pandoc本身很庞大,并且是 Haskell 编写,本文作者表示改不动;另外,直接 out-of-box 的装上之后,块公式pandoc总是会多生成\[ ... \]的 pair,决定弃坑- 网络上还存在一些 patch 方案,比如这里,直接把 
marked的 inline rule 改掉,让其不再将_作为合法的强调标志(比如_asdf_之类就不会渲染成 asdf 了) - 其实也可以 摆大烂,把所有 LaTeX 和 Markdown 冲突的关键字都用反斜杠转义掉
 
可以看到都不是太优雅。
改动简介
其实一开始想给
hexo-renderer-marked写插件,但是它只支持 extendTokenizer和Renderer,把那些乱七八糟规则再写一遍又很难维护,所以最后放弃了这个想法。
主要是对 marked 进行改动,让其支持 $$ .. $$ 和 $ .. $ 的 Tokenize,并且能无转义的输出。
marked 采用正则表达式不断匹配的方式进行词法分析,对于部分块对象会继续进行行内的词法分析。词法分析后的 Toekn 流会送到 Renderer 进行输出。
详细可以看 libreliu/marked 上面的提交。
由于人比较懒,没有在 npm 上加自己的包,而是直接
1  | npm install github:libreliu/hexo-renderer-marked-math#master --save  | 
这个的缺点是每次 npm update hexo-renderer-marked-math 都要重新拉,并且版本管理上不是很友好。不过只是自己用的话其实无所谓。
(作为菜鸡)踩过的坑
NodeJS 的
require在找不到index.js时,会去package.json中查找main字段,并且加载对应的模块。可以注意到,
marked的main是./lib/marked.cjs,这个文件需要运行npm run build生成。调试 Promise 链可以采用 Bluebird 的Promise.longStackTraces()。
相关工作
这里在 2015 年对 VSCode 的 Markdown 渲染的 patch 对本更改有参考意义。
math-marked这个项目在我基本写完之后才看到,不过作者没有基于原来的 commit 继续改,后续升版本会比较费劲。