Mathjax 2.x与3.x对比与升级

275 阅读5分钟

后续用了4.0.0的beta版本,原因见结尾!

背景

有道小P的前端代码是从硬件中拉的,用的是mathjax2.7.6版本,压缩前体积有150M,并有数万个小文件。

在ios中,解压后的文件最低占用4.1KB,导致第一版,在ios应用市场上体积去到了300+M。

出于加载速度的优化,对前端资源包作了离线处理,因此,mathjax部分也需要完整的拷贝进前端包

!image.png

产生原因

  • mathjax2的使用中,先加载入口文件mathjax/mathjax.js?xxx,再根据实际要展示的内容,加载其他需要的资源文件,实际依赖是不确定的

    • 可以拷贝这份html,修改里面的latex公式后,加载的js文件会有所不同

因此,mathjax2中,哪怕我只需要tex2svg的内容,其他形式的转换并不需要,最稳妥的方法也是将整个文件夹拷贝下来,避免渲染时丢失文件

当然,mathjax2拷贝下来的一些没配置的文件是可以直接删除的:

  1. 字体文件、其它的的转换方法文件等
  2. 项目中只需要支持latex公式,因此用于支持mathMl、AsciiMath格式的文件也可以直接删掉

在这之后上,难以确定哪些文件是完全不需要的

方案

对比mathjax2与mathjax3

mathjax3与mathjax2主要有有下列区别:

  1. 好处

    1. mathjax3重构了2,渲染流程

    2. 渲染性能优化,特别是在启动时间上,因为采用了新的架构,此外,mathjax2是较早的版本,涉及到IE浏览器等兼容场景,而3并没有

    3. 实现了组件,对不同的转换方式抽离成了单独的文件,配置更灵活

      1. 有效解决了使用时不存在依赖不确定的问题
      2. 体积更小 -小很多那种小!
    4. 一些需要在mathjax2中额外配置的扩展,在3中是默认加载的

  2. 坏处

    1. api与配置的变化、兼容性等,需要重新配置效果
    2. 同时3移除了一些配置
    3. 3并没有完全移植2的内容,因为还在迭代中,如扩展autobold等
    4. 2的HTML-CSS配置中支持STIX与TEX字体,3仅支持TEX字体
    5. (后续补充)mathajx3不支持自动换行

综上分析,升级到mathjax3虽然也有弊,但是影响都不大,体积优化上利大于弊

升级实践

  1. 配置调整 :利用2->3配置转换地址,会给出转换后的配置以及一些注意事项

  2. 插件扩展:

    1. 小P项目中,mathajax2使用了如下插件,这些插件都需要额外加载,并在加载成功后重新注入到mathjax中

      1. ["AMSmath.js","AMSsymbols.js","extpfeil.js","mhchem.js", "autobold.js", "enclose.js", "color.js"]
      2. 上述依赖除不被支持的autobold外,都已经内置到mathjax3中的tex-svg.js文件中,因此不再需要显式引入
    2. 将2中显式引入插件的相关代码删除,因为3中被自动引入了

  3. 渲染某个元素的写法,变成了promise而不是callback的形式

// mathjax3
const rendMath = (mathEle, callback) => {
  const mathContent = mathEle || document.body;
  if (window.MathJax) {
    // 使用MathJax.typesetPromise进行异步渲染
    window.MathJax.typesetPromise([mathContent]).then(() => {
      // 类型设置完成后,执行回调函数
      if (callback) {
        callback();
      }
    }).catch((error) => {
      console.error('MathJax typesetting failed:', error);
    });
  }
}

升级效果

mathjax2升级为mathjax3后

  1. 同样是tex2svg的功能,mathjax3只需要几百KB,mathjax在稳妥的情况下则需要100+MB,体积减少了99%

  2. 渲染速度更快

  3. 引入的文件从数万个文件变成一个

后续 - 升级为4.0.0的版本

异常现象:

使用mathjax3后,公式过长的渲染(mathjax2没有这个问题)

image.png

豆包的公式渲染用的是mathjax3.2.2,也存在这个溢出无法换行的问题

image.png

产生原因:

mathajx3并不支持自动换行,当回答中渲染的公式很长时,会出现页面溢出的现象

且尝试通过设置元素宽度(等比例缩小,导致无法看清)、设置css属性white-space / word-break,均无法解决

image.png

解决方案

升级至mathjax4

通过github issue,在mathajx4-beta版本已经实现了换行内容

mathjax4的改动内容见文档,对使用中有影响的主要是下面两个

  1. 增加自动换行属性,可以这样配置

MathJax = {
  svg: {
    linebreaks: {                  // options for when overflow is linebreak
      inline: true,                   // true for browser-based breaking of inline equations
      width: '100%',                  // a fixed size or a percentage of the container width
      lineleading: .2,                // the default lineleading in em units
      LinebreakVisitor: null,         // The LinebreakVisitor to use
    }
  }
}
  1. 修改了默认字体,且增加了可使用的字体(mathjax3只支持一种字体),可通过下列属性配置
MathJax = {
	...
      output:{
        font:'mathjax-tex'
      }
	...
}
  1. 点击公式和有较大概率出现弹窗,检查发现是因为4默认启用了无障碍功能,会显示公式字符与盲文(mathjax3也启用了,但点击后不会有弹窗,4会有)

    1. 点击公式字母后的弹窗示意图

      1. image.png
    2.  调用的位置(浏览器中调试后定位到)

      1. image.png
    3. 解决:关闭无障碍配置的部分交互,因为我们的项目不考虑该场景(无障碍配置文档:docs.mathjax.org/en/latest/o…)


MathJax = {
  ...
  options: {
    a11y: {
      speech: false,                      // switch on speech output
      braille: false,                     // switch on Braille output
      subtitles: false,                   // show speech as a subtitle
      viewBraille: false,                // display Braille output as subtitles
    }
  }
  ...
};
  1. (后续)回答中有大量公式时候,渲染缓慢,在安卓耗时20s+,ios4s+

    1. 背景:对接高教社合作时,回答中会有大量的公式(高数内容等),导致页面渲染卡顿

    2. 解决:分析后,耗时集中是在Latex的渲染,且经过尝试,是默认开启辅助性功能导致的卡顿,关闭即可

      1. github issue:github.com/mathjax/Mat…

      2. 前面第3点中也有关闭部分的功能,这里是完全关闭了

      3. 配置(注意,下面的配置方法仅对mathjax4生效)


MathJax = {
  ...
  options: {
    menuOptions: {
		settings:{
			enrich: false
		}
	}
  }
  ...
};

效果:渲染时间降低到2s内,减少了90%的渲染时间

目前小P项目中的static/mathjax/4.0.0-beta.6/tex-svg.js文件的来源是:

github.com/mathjax/Mat…

需要留意的是,mathjax4是beta版本,因此需要充分的测试渲染效果

最终效果

image.png

另一个回答的效果对比:

image.png