vitepress
vitepress copied to clipboard
equation numbering in math with markdown-it-mathjax3 triggers duplicate label errors
Describe the bug
I'm using vitepress with math through markdown-it-mathjax3 as shown in the documentation. When I write equations with numbering and labels I get errors in dev mode about duplicate labels being defined. If I turn off duplicate label errors in the config then whenever there is an update in dev mode the equation numbering increases.
Reproduction
- Enable
mathand installmarkdown-it-mathjax3 - Create a simple page with an equation using
\begin{align} ... \label{eq} \end{align} - Run vitepress in dev mode
Expected behavior
Equations should be shown and numbered starting at 1 even when updating the markdown page and using hmr.
System Info
System:
OS: macOS 15.4.1
CPU: (12) arm64 Apple M2 Pro
Memory: 168.23 MB / 32.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 22.14.0 - ~/.nvm/versions/node/v22.14.0/bin/node
Yarn: 4.5.1 - ~/.nvm/versions/node/v22.14.0/bin/yarn
npm: 10.9.2 - ~/.nvm/versions/node/v22.14.0/bin/npm
Browsers:
Chrome: 136.0.7103.93
Chrome Canary: 138.0.7168.0
Edge: 136.0.3240.50
Safari: 18.4
Safari Technology Preview: 18.4
Additional context
The problem is caused by mathjax needing a state reset (through texReset) whenever content is re-rendered. Otherwise the state contains previously defined labels and equation numbering. I managed to work around this locally by forking markdown-it-mathjax3 and monkey patching md.render so reset the InputJax state:
// Patch of original plugin. Monkey patch md.render and reset InputJax to fix equation label
// counts and refs
const originalRender = md.render;
md.render = function (src: string, env?: any) {
documentOptions.InputJax.reset();
return originalRender.call(this, src, env);
};
This isn't a proper solution of course, and I'm not sure there is something vitepress can do by itself, or if this would need to be fixed in the plugin and/or markdown-it.
Relevant markdown-it-mathjax3 issue: https://github.com/tani/markdown-it-mathjax3/issues/55#issuecomment-1100608009
Validations
- [x] Check if you're on the latest VitePress version.
- [x] Follow our Code of Conduct
- [x] Read the docs.
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
Hmm, yeah not sure what we can do here since it doesn't expose the mathjax instance. Maybe you can use some different plugin for now:
In .vitepress/config.ts
import { createMathjaxInstance, mathjax } from '@mdit/plugin-mathjax'
import { defineConfig } from 'vitepress'
const mathjaxInstance = createMathjaxInstance({
transformer: (content) => content.replace(/^<mjx-container/, '<mjx-container v-pre'),
tex: {
tags: 'ams'
}
})!
const virtualModuleId = 'virtual:mathjax-styles.css'
const resolvedVirtualModuleId = '\0' + virtualModuleId
export default defineConfig({
markdown: {
config(md) {
md.use(mathjax, mathjaxInstance)
const orig = md.renderAsync // use md.render if you're on vitepress v1
md.renderAsync = function (...args) {
mathjaxInstance.reset()
return orig.apply(this, args)
}
}
},
vite: {
plugins: [
{
name: 'mathjax-styles',
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return mathjaxInstance.outputStyle()
}
}
}
]
}
})
In .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import 'virtual:mathjax-styles.css'
export default DefaultTheme
HMR for mathjax css is not implemented. I don't think it's necessary but it is straightforward to add:
// ...
import type { ViteDevServer } from 'vite'
let server: ViteDevServer | undefined
// ...
md.renderAsync = async function (...args) {
mathjaxInstance.reset()
const res = await orig.apply(this, args)
if (server) {
const mod = server.moduleGraph.getModuleById(resolvedVirtualModuleId)
if (mod) {
server.moduleGraph.invalidateModule(mod)
server.reloadModule(mod)
}
}
return res
}
// ...
vite: {
plugins: [
{
name: 'mathjax-styles',
configureServer(_server) {
server = _server
},
// ...
@brc-dd I tried your suggestion, but for me this leads to a FATAL ERROR: Reached heap limit Allocation failed after about 7 hmr reloads :/
With the markdown-it-mathjax3 this only happens after around 22 hmr.
I could not figure out what is eating memory yet, but I suspect it has to do with mathjax