mathjax/MathJax-src · 上手攻略
- 仓库:mathjax/MathJax-src
- 链接:https://github.com/mathjax/MathJax-src
- 分类:academic-writing / 渲染引擎
- 作者:spark
- 更新:2026-08-20
是什么
mathjax/MathJax-src 是 MathJax v3 及之后版本的源代码仓库(TypeScript 编写)。MathJax 本身是一个开源的浏览器/Node.js 数学公式渲染引擎,支持 LaTeX、MathML、AsciiMath 三种输入语法,自带无障碍支持(屏幕阅读器 + expression explorer),浏览器用户零安装(纯 CDN <script> 即可)。
需要特别注意区分两个仓库:
| 仓库 | 用途 |
|---|---|
mathjax/MathJax-src(本文) |
源代码仓库,作者从源码构建、贡献 TS 代码、自定义 component 时使用 |
mathjax/MathJax |
预编译 component 仓库,日常 CDN/npm 装包走这里 |
日常开发者一般不需要 clone MathJax-src,只 npm install mathjax@4 或加 CDN script 即可。本攻略主要面向想读源码 / 自定义 component / 贡献 PR 的读者。
解决什么问题
- 浏览器端数学公式排版:论文博客(博客园、知乎、Hexo、Jekyll、Hugo、Quarto)需要 LaTeX → SVG/HTML 渲染,MathJax 是事实标准。
- 学术写作工具链的"公式段":
tikzplotlib(matlibplot → TikZ)、kingyiusuen/image-to-latex(图片 → LaTeX)负责"产出",MathJax 负责"在网页里显示"。 - Node.js 端离线公式→SVG:
mathjax包提供tex2svgPromise,适合 SSR、报告生成、PDF 流水线的前置步骤。 - 可访问性 / 屏幕阅读器:MathJax 内建 ARIA、speech、explorer,远比手写 MathML 友好。
快速安装
方式 A:浏览器端最简方案(90% 用户只用这个)
<script src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js" defer></script>
无需 git clone、无需 npm install。jsDelivr / unpkg 都托管了官方 component bundle。
方式 B:Node.js 端(SSR / 报告生成)
npm install mathjax@4
最小调用:
import MathJax from 'mathjax';
await MathJax.init({
loader: { load: ['input/tex', 'output/svg'] }
});
const svg = await MathJax.tex2svgPromise('\\frac{1}{x^2-1}', { display: true });
console.log(MathJax.startup.adaptor.serializeXML(svg));
ES5 环境用 require('mathjax') + .then() 链,文档里有等价样例。
方式 C:从源码安装(贡献者)
git clone https://github.com/mathjax/MathJax-src.git
cd MathJax-src
npm install
npm install @mathjax/src
@mathjax/src 包提供:
ts/—— TypeScript 源码js/—— 已编译 JavaScriptcomponents/—— component 构建工具 + 控制文件bundle/—— 打包产物
核心用法
1. 浏览器端 TeX 输入
直接在网页写:
<p>When \(a \ne 0\), there are two solutions to \(ax^2 + bx + c = 0\).</p>
<script>
window.MathJax = {
tex: {
inlineMath: [['\(', '\)']],
displayMath: [['$$', '$$'], ['\[', '\]']]
}
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js" defer></script>
2. MathML + AsciiMath 混合输入
加载 mml-chtml.js(只 MathML)或 tex-mml-chtml.js(全功能):
<script src="https://cdn.jsdelivr.net/npm/mathjax@4/mml-chtml.js" defer></script>
3. Node.js 批量转换(适合 Quarto / Pandoc 流水线前置)
import MathJax from 'mathjax';
import { promises as fs } from 'fs';
await MathJax.init({ loader: { load: ['input/tex', 'output/svg'] } });
const tex = await fs.readFile('equation.tex', 'utf8');
const svg = await MathJax.tex2svgPromise(tex, { display: true });
await fs.writeFile('equation.svg', MathJax.startup.adaptor.serializeXML(svg));
4. 自定义 Component(高级)
源码仓提供了 component 构建工具链(components/ 目录 + 控制文件),常见需求:
- 裁剪 input/output 模块,把 bundle 缩到最小
- 替换字体
- 加自定义 TeX 宏
构建示例(以官方 docs 为准):
npm run make-component # 或 ts-node components/make-component.ts src/components/my-min.ts
⚠️ 自定义 component 的官方文档在 docs/mathjax/components/,社区经验显示这是 v3 → v4 最容易踩坑的地方,直接复用官方 component + lazy loader 通常比手搓更划算。
典型适用场景
- 学术博客 / 笔记软件:Hugo、Hexo、Jekyll、Quarto 内置 MathJax 支持,加一行 frontmatter 即可。
- 学术 paper 写作:arXiv 编译、PDF 生成(MathJax 输出 SVG 再交给 LaTeX 模板)。
- AI 生成的数学教学页面:LLM 写 LaTeX 公式 → 直接渲染在页面,无需服务端。
- 图像公式转 LaTeX 后的浏览器复核:
kingyiusuen/image-to-latex等工具输出 LaTeX 后,用 MathJax 在浏览器里复核,比硬读 LaTeX 快。 - Node.js SSR / 静态站点生成:在构建时把
.tex一次性烘焙成 SVG,运行时无 JS 依赖。 - 可访问性需求强的政府 / 高校站点:MathJax 的 speech + explorer 满足 WCAG / Section 508 合规。
坑与注意
⚠️ MathJax-src ≠ MathJax:多数用户应该用 mathjax/MathJax(预编译)或 npm 包 mathjax,而不是 clone 源码仓。源码仓 2k+ stars 大部分是 contributor,不是 end user。
⚠️ v4 与 v2/v3 API 差异显著:v2 的 MathJax.Hub 在 v3 已被 mathjax.init() 取代,旧教程基本失效。如果维护老项目遇到 MathJax.Hub.Config 之类的写法,说明是 v2 时代,迁移指南见 docs.mathjax.org。
⚠️ CDN 选择:jsDelivr / unpkg 都行,但不要混用不同版本:同一个页面同时加载 mathjax@3 和 mathjax@4 会冲突,只显示先加载的版本。
⚠️ Node 端的 DOM 依赖:MathJax.init() 在 Node 下需要 alternate DOM 实现(linkededom 或 jsdom),这是 Node-only 路径。在浏览器里 require('mathjax') 跑 init() 是错的,浏览器应该用 component bundle + lazy config。
⚠️ CHTML vs SVG vs CommonHTML:输出格式影响可访问性 + 排版精度。CHTML(CommonHTML)最像 LaTeX 排版;SVG 矢量、可独立嵌入;HTML/CSS 输出文件最小但屏幕阅读器支持弱。
⚠️ 大型文档性能:几百 KB 的论文 MathJax 化时,首屏渲染可能卡顿。解决:loader.load 分块、按页 lazy、defer script 标签。
⚠️ 分支与版本:main 分支为开发版,develop 分支为下一个 minor 发布,生产环境钉死某个 release(如 mathjax@4.x)。
与同类对比
| 项目 | 输入 | 输出 | 浏览器/Node | 依赖 |
|---|---|---|---|---|
| MathJax v3/v4(本文) | LaTeX/MathML/AsciiMath | SVG/CHTML/HTML | 都支持 | TS → JS,bundle 自带字体 |
| KaTeX | LaTeX 子集 | HTML + CSS | 都支持 | 更快、更小,但 LaTeX 不完全 |
| MathML 原生 | MathML | HTML | 浏览器原生 | 0 依赖,但支持度参差(Chrome 强、Safari 弱) |
| LaTeX → 图片(server) | LaTeX | PNG/SVG | 服务端 | 需要 LaTeX 编译器,慢且重 |
| MathJax v2 | 同上 | 同上 | 都支持 | 已 EOL,API 与 v3+ 不兼容 |
MathJax 的核心优势是 LaTeX 兼容性最广(几乎完整 TeX 语义),KaTeX 更快更轻但复杂公式会渲染失败;选择标准:你的公式如果含 \label/\ref、align、cases、自定义宏,MathJax 几乎是唯一靠谱选择;纯分数/上下标/根号/积分,KaTeX 更快。
一句话推荐结论
学术博客 + 复杂 LaTeX 公式用 MathJax;博客渲染速度优先 + 公式简单的场景用 KaTeX;只 clone MathJax-src 的场景是"我要改源码或贡献 PR"。
进阶:MathJax 的架构与扩展点
读完 README + 仓库结构后,有几个工程决策值得工程团队理解:
1. TypeScript 编译链
ts/ 是 TS 源码,js/ 是编译产物,用户拿到的 npm install mathjax 是组件化的 bundle,不是源码。意味着:
- 普通用户不能直接 hack MathJax 行为——必须 fork 源码仓,改 TS,重新 build component。
- 自定义扩展要走"扩展包"机制(
window.MathJax = { ... }注册 loader),而不是 monkey patch。 - 编译链对贡献者要求较高,PR 评审周期长(issue 跟踪看,平均 1-3 周)。
2. Component 抽象
MathJax v3+ 引入了"Component"概念:一组 input/output/extension 的可重用单元。常见 component:
| Component 名 | 输入 | 输出 | 体积 |
|---|---|---|---|
tex-mml-chtml.js |
TeX + MathML + AsciiMath | CHTML | ~250KB gzip |
tex-svg.js |
TeX | SVG | ~400KB gzip |
mml-chtml.js |
MathML | CHTML | ~150KB gzip |
tex-chtml.js |
TeX | CHTML | ~200KB gzip |
经验法则:只加载你需要的 input + output。如果只用 TeX + CHTML,不要用 tex-mml-chtml.js(多了 MathML 解析器)。官方提供 component builder 工具裁剪。
3. 浏览器 vs Node 的 init 差异
这是 v3+ 最容易踩的设计点。Node 端需要 alternate DOM(linkedom 或 jsdom):
// Node 端(SSR / 报告生成)
import { JSDOM } from 'jsdom';
const dom = new JSDOM('<!DOCTYPE html>');
global.document = dom.window.document;
global.window = dom.window;
// 然后才能 MathJax.init()
浏览器端不需要这套,直接 <script> 加载即可。这就是 README 强调"this method sets up an alternative DOM implementation which you don't need in the browser"的原因。
4. 输出格式选择决策树
需要矢量缩放? → SVG
↓ 否
需要屏幕阅读器支持? → CHTML
↓ 否
需要最小 bundle? → HTML(纯 CSS,仅限简单公式)
多数学术场景选 CHTML:屏幕阅读器支持最好、文本可选中复制、align 等环境排版最准。
5. 与学术写作工具链的协同
本仓库目录的兄弟项目:
mathjax/MathJax-demos-web—— 浏览器端 demomathjax/MathJax-demos-node—— Node 端 demonschloe/tikzplotlib(同目录选榜)—— matlibplot → TikZ,前端用 MathJax 渲染 TikZ 输出kingyiusuen/image-to-latex(同目录选榜)—— 图片公式 → LaTeX 源码,仍需 MathJax 在浏览器复核
工作流示意:
matlibplot → tikzplotlib → .tex 源码
↓
MathJax 浏览器渲染
↓
最终页面
或者:
公式截图 → image-to-latex → .tex 源码
↓
MathJax 浏览器复核
↓
修正后嵌入论文
6. 字体与本地化
MathJax 默认走 CDN 字体(Web Font)。如果你的场景要求完全离线(政府内网、企业内网、教学专网),需要:
- 从 GitHub release 下载字体文件(STIX 或 TeX 字体)
- 配置
MathJax.startup.output.font.URL指到本地路径 - 关闭 CDN 引用
7. 性能:大文档的渲染策略
几百 KB 文档 MathJax 化时,首屏渲染可能卡顿。常见优化:
- 分块渲染:
MathJax.typesetPromise(elements)只 typeset 指定 DOM 节点,而不是全文档 - 延迟渲染:滚动到公式可视区才渲染(IntersectionObserver + lazy typeset)
- 服务端预渲染:Node 端在 build 时把 .tex → SVG,运行时无 JS 依赖
8. v2 → v3+ 迁移要点
如果你接手 v2 老项目,迁移指南核心差异:
| v2 API | v3+ API |
|---|---|
MathJax.Hub.Config({...}) |
window.MathJax = {...} 在 script 加载前声明 |
MathJax.Hub.Queue(["Typeset", ...]) |
MathJax.startup.promise 或 typesetPromise(...) |
MathJax.Hub.Register.StartupHook(...) |
MathJax.startup.registerStartupListener(...) |
TeX 配置在 tex2jax |
TeX 配置在 tex |
MathJax.Hub.processSectionDelay |
等价 MathJax.startup.adaptiveCSS 或 renderActions |
不要在 v3+ 写 MathJax.Hub,那是 v2 残留。
决策清单:什么时候用 / 不用
✅ 用 MathJax v4:
- 论文博客 / 学术 Wiki
- 公式含 align / cases / array / 自定义宏
- 需要可访问性(政府 / 高校 / 无障碍合规)
- 团队对 TypeScript 工具链熟悉
❌ 不用 / 用 KaTeX: - 公式简单(分数 / 上下标 / 根号 / 积分) - 渲染速度敏感(评论区 / 实时聊天 / 移动端) - 不需要屏幕阅读器支持 - bundle 体积敏感(嵌入式场景)
❌ 不要 clone MathJax-src:
- 普通用户(用 mathjax/MathJax 或 npm install mathjax@4)
- 只想要 component 裁剪(用官方 component builder,不需要源码)
主要来源
- 仓库 README:https://github.com/mathjax/MathJax-src
- 官方文档:https://docs.mathjax.org
- npm:mathjax@4(运行时)、@mathjax/src(源码包)
- CDN:jsDelivr https://cdn.jsdelivr.net/npm/mathjax@4/tex-mml-chtml.js
- Node Demos:https://github.com/mathjax/MathJax-demos-node
- Web Demos:https://github.com/mathjax/MathJax-demos-web
- 当前 release 分支:release-v4(npm 主版本)