用 QuickJS 打包编译 KaTex 作为后端公式渲染引擎

陪她去流浪 桃子 2024年06月17日 编辑 阅读次数:346

因为发现某篇文章含有较多的公式、而复杂的 #MathJax 在前端渲染又较慢1的问题,所以决定把 MathJax 迁移到后端(服务端渲染)。 但是调研一遍后发现我需要在后端引入重量级庞然大物 #NodeJS,虽然代码已经写好、测试好2, 但是最终,这两个条件加在一起,我还是放弃了这个方案没有合并进主干。 取而代之的是,一个更精练(“够用!”3——褒义)的数学公式渲染库:KaTex 出现在了我眼帘。 当然,#KaTex 也是用 Javascript 实现的,仍然避免不了安排一个后端 Javascript Engine 的问题。 不一样的是,KaTex 对 Engine 自身的基础库并没有太多的要求,尽管官方文档仍然以 NodeJS 作为服务端渲染的例子4, 但是我本人首先考虑的却是用来自 Fabrice Bellard5 的 小巧、嵌入式、完整的 Javascript Engine:QuickJS。 已经关注 #QuickJS 很多年,只是没想到第一次上生产环境是这种场合。

编译 QuickJS

可以选择用包管理工具安装(比如 apk add quickjs quickjs-dev),也可以下载源代码自行编译(make)。 我在 Mac 上自行编译的源代码,而在容器里面直接用上述 apk 安装的,由于几乎没有依赖,所以过程十分快速又容易。

1
2
3
4
quickjs-2024-01-13 $ ./qjsc -h
QuickJS Compiler version 2024-01-13
usage: qjsc [options] [files]
...

QuickJS 本身相对来说已经非常小巧:

1
2
3
quickjs-2024-01-13 $ ls -lh qjs{,c}
-rwxr-xr-x  1 tao  staff   1.1M Jun 13 21:19 qjs
-rwxr-xr-x  1 tao  staff   1.0M Jun 13 21:18 qjsc

前者是交互式执行环境(repl);后者是编译工具,可以把 JS 编译成一个可执行的二进制文件(打包)。

测试打包 KaTex

直接去 GitHub 上下载,解包后的 katex.min.js (275KB) 就是我们所需。

用 QuickJS 编译它也非常简单:

1
$ ./qjsc katex.min.js 

上面只是测试是否可以编译,结果是:很快,完全没有任何错误。 但是,上面的编译结果还不足以渲染数学公式,因为 katex.min.js 只是一个库,它还没有被调用——以实现渲染功能。

编写渲染代码

KaTex 的使用参考官方文档即可。以下是我的测试用例(main.js):

1
2
3
4
5
import * as std from "std";

const tex = std.in.readAsString();
const html = katex.renderToString(tex);
std.out.puts(html);

因为 QuickJS 环境并没有网络库(net/http),所以:

  1. 读取 Tex 公式
  2. 输出 HTML 内容

这两个步骤我是通过标准输入和标准输出完成的6(被 QuickJS 实现在 std 包里面)。

然后需要把这两个文件一起打包编译:

1
$ ./qjsc katex.min.js main.js

结果会生成 a.out 文件7

1
2
$ ls -lh a.out
-rwxr-xr-x  1 tao  staff   1.3M Jun 17 21:02 a.out

测试一下也完好工作():

1
2
3
$ ./a.out <<< $'x = {-b \pm \sqrt{b^2-4ac} \over 2a}.'
<span class="katex"><span class="katex-mathml">
...

最后

一些说明:

  1. KaTex 也随附了样式文件(katex.min.css)和字体文件(fonts/),需要前端可访问;
  2. KaTex 本身也有一些较少的选项可以配置,实现上,可以把 公式 和 选项 作为 JSON 一同传入;

无论如何,可以参考我在我博客上的实现:服务端渲染数学公式(MathJax→KaTex)


  1. 会请求很多外部资源(样式、脚本和字体),并且会 reflow 页面。以及很多 a11y 的东西,这方面我目前没有用心关注,这方面做得最好的应该是苹果公司,没有之一。 ^

  2. 后端渲染数学公式。 ^

  3. 我写数学公式的场合其实很少。 ^

  4. https://katex.org/docs/node 。 ^

  5. 一位知名的天才级程序员、计算机科学家、数学家,开发了诸多知名项目:FFMPEG / QEMU 等。主页:https://bellard.org/。 ^

  6. 为了性能考虑,可以实现“进程内”网络支持,或者缓存公式渲染结果。 ^

  7. 如果参考 QuickJS 的命令行说明去掉一些不必须的内置库,这个文件大小结果会减半。 ^

标签:NodeJS · MathJax · KaTex · QuickJS