用 MCP 定位并修复 Fluid 的 MathJax startup.document 报错
最近在本地预览(http://localhost:4000)时,进入文章页会在控制台看到一条红色报错:
Cannot read properties of undefined (reading 'document')
这次用 Codex CLI + MCP chrome-devtools 复现并定位,最后确认是 Fluid 主题的 MathJax 插件逻辑 与我在 _config.fluid.yml 里 提前注入 window.MathJax 配置 发生冲突导致。
复现步骤(MCP)
- 本地已启动
hexo server(默认http://localhost:4000)。 - 使用 MCP
chrome-devtools打开首页http://localhost:4000/。 - 点击首页的第一篇文章进入详情页。
- 读取控制台消息,出现报错:
1 | |
定位过程
1) 从报错关键词判断方向
报错是“读取 xxx.document 时 xxx 为 undefined”。结合页面开启了 MathJax(文章 front-matter math: true),优先怀疑 MathJax 的 startup.document 相关逻辑。
2) 在主题中找到访问点
在主题代码里搜索 startup.document,定位到:
node_modules/hexo-theme-fluid/layout/_partials/plugins/math.ejs:29
该文件里有一段逻辑(节选):
1 | |
也就是说:只要 window.MathJax 在此时“已经存在”,就会走到 else 分支并立即访问 MathJax.startup.document。
根因分析
我在 _config.fluid.yml 的 custom_head 中写了类似下面的配置(旧写法):
1 | |
这段“只是想提前塞配置”,但副作用是:
math.ejs看到window.MathJax已经有值,误判为“MathJax 已加载”。- 于是直接执行
MathJax.startup.document.state(0)。 - 但此时真正的 MathJax 库(
tex-mml-chtml.js)还没加载完成,startup还不存在,最终报错。
修复方案
目标:不要在 MathJax 库加载前,把 window.MathJax 变成一个“真值对象”,但仍然能把自定义配置合并进去。
我采用的做法是:在 custom_head 里用 Object.defineProperty 拦截主题对 window.MathJax 的赋值,然后在 setter 里合并 physics 与 tex.tags = 'ams' 等配置。
- 代码位置:
_config.fluid.yml(custom_head段落) - 关键点:getter 返回
undefined,确保主题走if (!window.MathJax)分支;真正赋值发生在主题设置默认配置时,由 setter 接管并合并。
验证方式
- 重启本地服务(例如
npm run server或hexo server)。 - 再次进入任意
math: true的文章页。 - 控制台不再出现
startup.document相关报错;MathJax 自动编号与physics扩展正常。
备选方案(不推荐但可用)
也可以直接修改主题文件 node_modules/hexo-theme-fluid/layout/_partials/plugins/math.ejs,把 else 分支改成更严格的判断(例如判断 MathJax.startup && MathJax.startup.document)。
但这属于直接改 node_modules:
- 版本升级/重装依赖后会被覆盖
- 不利于长期维护
因此更推荐通过 _config.fluid.yml / source/custom/ 这类“可控注入点”解决。