Self-hosted MathJax

Self-hosted MathJax

This directory contains a vendored copy of MathJax v4.1.2 (the tex-chtml configuration) plus the mathjax-newcm font it renders with. It is served from our own origin and loaded by _includes/mathjax-custom.html on any page with use_math: true in its front matter.

Why it’s vendored (not loaded from a CDN)

The site previously loaded MathJax from https://cdn.mathjax.org/.... That CDN was retired in 2017 and now serves only a tiny JS shim that redirects to cdnjs.cloudflare.com. The math therefore depended on two third-party domains plus runtime script injection.

Some corporate networks (VPN / proxy / Zscaler-style TLS interception) block or break those external requests, which made math fail to render — readers on those machines saw raw $...$ LaTeX instead of equations.

Self-hosting removes every external domain from the math path. If a reader can load the blog, they can load the math engine, because it comes from the same origin.

v4 note: In MathJax v3 the font was bundled inside tex-chtml.js. In v4 the font is a separate package (default mathjax-newcm) that the engine fetches at runtime — from a CDN unless told otherwise. So the font is vendored here too, and _includes/mathjax-custom.html sets output.fontPath to this directory. Without that, self-hosting the engine alone would silently reintroduce the CDN dependency for fonts.

Why v4 (and displayOverflow: 'scale')

v4 added the output.displayOverflow option. We set it to 'scale', which shrinks any display equation that is too wide for the 740px content column so it stays fully visible and centered instead of overflowing into the sticky table of contents on the right. v3 had no built-in way to do this.

What’s included

To keep the footprint small (~3.7 MB instead of the full ~19 MB engine + ~50 MB font distribution), only the files actually loaded at runtime are vendored:

  • tex-chtml.js — the combined TeX-input + CommonHTML-output component ([mathjax]).
  • input/tex/extensions/ — TeX extensions autoloaded on demand (e.g. \color, \cancel, \require{...}).
  • fonts/mathjax-newcm-font/ — the CommonHTML newcm font: its chtml.js entry plus chtml/woff2/ (the WOFF2 files) and chtml/dynamic/ (ranges loaded on demand, e.g. arrows, accents). Resolved via output.fontPath.../fonts/%%FONT%%-font.

The SVG output, MathML input bundles, the speech-rule engine (sre), the UI menu, and the font’s svg/ + CommonJS/ESM (cjs/, mjs/) builds were intentionally excluded — they are not used by this config.

How to update

To bump the version, re-vendor both the engine and the font (they share a version line):

# 1. Download and extract the engine and the newcm font npm tarballs
npm pack mathjax@<VERSION>
npm pack @mathjax/mathjax-newcm-font@<VERSION>
tar -xzf mathjax-<VERSION>.tgz                       # -> package/
tar -xzf mathjax-mathjax-newcm-font-<VERSION>.tgz -C font   # -> font/package/

# 2. Replace the vendored engine paths (package/ is the tarball root in v4 — no es5/)
rm -rf assets/mathjax/tex-chtml.js assets/mathjax/input
cp    package/tex-chtml.js        assets/mathjax/
cp -R package/input/tex/extensions assets/mathjax/input/tex/extensions

# 3. Replace the vendored font (CHTML only)
rm -rf assets/mathjax/fonts/mathjax-newcm-font
mkdir -p assets/mathjax/fonts/mathjax-newcm-font/chtml
cp    font/package/chtml.js        assets/mathjax/fonts/mathjax-newcm-font/
cp -R font/package/chtml/woff2     assets/mathjax/fonts/mathjax-newcm-font/chtml/woff2
cp -R font/package/chtml/dynamic   assets/mathjax/fonts/mathjax-newcm-font/chtml/dynamic

# 4. Rebuild and verify a math post renders (see below)

Verifying

bundle exec jekyll build

Then open any use_math: true post (e.g. /Reasoning-Models/) and confirm:

  • equations render with the newcm font and the browser console shows no MathJax errors,
  • the Network tab shows the font loading from this origin (/assets/mathjax/fonts/...), not from a cdn.jsdelivr.net / *.mathjax.org URL,
  • a very wide display equation shrinks to fit the column instead of overflowing right.