logo

使用Wujie时遇到的mathjax加载问题

07:04

阅读次数: 0

最近项目使用wujie进行重构,但是遇到了一些问题。

原来的项目引入了mathjax来进行数学公式的展示,但是,在作为wujie的子应用的时候。mathjax 无法成功加载。 先看看老项目是怎么加载的:

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
	jax: ['input/TeX', 'output/HTML-CSS', 'output/SVG'],
	messageStyle: 'none',
	displayAlign: 'left',
	skipStartupTypeset: true,
});

</script>

<script src="https://oss.example.cn/mathjax/mathjax_config.js?rev=1.0.7"></script>

<script src="https://oss.example.cn/mathjax/MathJax.js?config=TeX-AMS_HTML"></script>

在head中引入MathJax 的时候,src后面有参数config=TeX-AMS_HTML。在普通项目中,这个参数是可以被mathjax读取到的。但是放到wujie中 ,config参数就无法读取了

那是因为wujie本身的加载外部脚本的机制导致的。

wujie 的加载

在wujie启动子应用的加载过程时,所有内联的脚本,都会被替换到iframe中。

wujie的沙箱原理,就是通过iframe运行js脚本,劫持js脚本中的dom变化,反应到wujie自己的webcomponent中 。

在wujie中,点开控制台就可以看到wujie的结构。

Snipaste_2025-01-24_14-25-15.png

上面的webcomponent才是最终展示在页面上的。

点开webcomponent内部的header,可以看到,这里面的都是老应用的head中的一些脚本,而script标签,都会被替换,变成了一个注释:

Snipaste_2025-01-24_14-28-41.png

注释中写明了replaced by wujie。

这是因为js脚本是不会让他在webcomponent内执行的。最终js脚本都会在iframe内执行。点开iframe的head,可以看到内部的script已经有了之前被替换掉的脚本。

Snipaste_2025-01-24_14-31-26.png

这样,wujie实现了把js放在一个沙箱内执行,而不影响其他的应用。

wujie沙箱的问题

但是,iframe和webcomponent配合实现的沙箱肯定不是万无一失的。 在一些老旧的脚本中,经常会通过扩展head来实现script的动态加载。 其实这样wujie也是会把script替换到iframe中的,但是卸载的时候,就会出现问题。 因为wujie已经代理了document对象,所有对document的操作,都会映射到webcomponent中,所以webcomponent中的script已经找不到了,变成了一串注释。

在这种情况下,只能通过设置jsignore,这个插件可以让wujie放弃代理document对象,所有的操作,又会回到iframe中。

但是又有一个棘手的情况,比如这次的mathjax。

mathjax 的加载过程

在mathjax的加载过程中,会读取src中的config参数,但是,通过我的调试发现,wujie替换之后,无法读取到config参数了。通过上面的wujie加载过程,可以看到,script标签中并没有保留config参数。

Snipaste_2025-01-24_14-50-13.png

mathjax加载时,会首先从页面的所有script中寻找Mathjax脚本,就是通过src判断是否相等,但这个时候,通过document查询script,会查到原来 的webcomponent里面。

script都没了,全变成注释了,这样还让mathjax怎么找config参数呢,没有了config参数,mathjax就开始自顾自的执行默认配置加载逻辑了,左下角还会出现加载message,还会显示加载失败!!!

找到问题的大致原因,就可以进行改进了,这里可以用wujie进行脚本替换,直接通过jsLoader插件,替换mathjax中出问题的代码,就是上面的b=(document.documentElement||document).getElementsByTagName("script");

        {
          jsLoader: (code: string, url: string) => {
            // 修复mathjax的脚本加载问题
            if (url.includes("mathjax")) {
              return code
                .replace(
                  'b=(document.documentElement||document).getElementsByTagName("script");',
                  'b = __WUJIE_RAW_WINDOW__.document.getElementsByTagName("script");',
                )
            }
            return code;
          },
        },

替换之后,mathjax加载脚本,就会从iframe中获取script。

logo