如何将解决vditor中katex未定义的问题

最近在项目中使用了vditor但是它的数学公式,流程图,脑图等都没法用,看了它的源码后,找到了解决方案,这里记录下。

简单来说,我的项目本身用了requirejs,windows上有require 的 define。

而我的项目现在想要使用vditor,但是引入vditor之后,我想用vditor的公式功能,它提示为katex is undefined。

去读vditor的源码发现,vditor是通过创建一个script标签,url设置为cdn中的katex.min.js,加载完成后,然后直接默认全局有了katex变量,于是就直接用了。

源代码部分如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import {Constants} from "../constants";
import {addScript, addScriptSync} from "../util/addScript";
import {addStyle} from "../util/addStyle";
import {code160to32} from "../util/code160to32";
import {mathRenderAdapter} from "./adapterRender";

declare const katex: {
renderToString(math: string, option: {
displayMode: boolean;
output: string;
macros: object;
}): string;
};

declare global {
interface Window {
MathJax: any;
}
}

export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?: IMath }) => {
const mathElements = mathRenderAdapter.getElements(element);

if (mathElements.length === 0) {
return;
}

const defaultOptions = {
cdn: Constants.CDN,
math: {
engine: "KaTeX",
inlineDigit: false,
macros: {},
},
};

if (options && options.math) {
options.math =
Object.assign({}, defaultOptions.math, options.math);
}
options = Object.assign({}, defaultOptions, options);

if (options.math.engine === "KaTeX") {
addStyle(`${options.cdn}/dist/js/katex/katex.min.css?v=0.16.9`, "vditorKatexStyle");
addScript(`${options.cdn}/dist/js/katex/katex.min.js?v=0.16.9`, "vditorKatexScript").then(() => {
addScript(`${options.cdn}/dist/js/katex/mhchem.min.js?v=0.16.9`, "vditorKatexChemScript").then(() => {
mathElements.forEach((mathElement) => {
if (mathElement.parentElement.classList.contains("vditor-wysiwyg__pre") ||
mathElement.parentElement.classList.contains("vditor-ir__marker--pre")) {
return;
}
if (mathElement.getAttribute("data-math")) {
return;
}
const math = code160to32(mathRenderAdapter.getCode(mathElement));
mathElement.setAttribute("data-math", math);
try {
mathElement.innerHTML = katex.renderToString(math, {
displayMode: mathElement.tagName === "DIV",
output: "html",
macros: options.math.macros,
});
} catch (e) {
mathElement.innerHTML = e.message;
mathElement.className = "language-math vditor-reset--error";
}

mathElement.addEventListener("copy", (event: ClipboardEvent) => {
event.stopPropagation();
event.preventDefault();
const vditorMathElement = (event.currentTarget as HTMLElement).closest(".language-math");
event.clipboardData.setData("text/html", vditorMathElement.innerHTML);
event.clipboardData.setData("text/plain",
vditorMathElement.getAttribute("data-math"));
});
});
});
});
} else if (options.math.engine === "MathJax") {
// ...
}
};

那么问题就成了,为什么执行了kate.min.js之后,全局没有katex变量了?

我们去看katex.min.js就会发现,它是webpack打包的产物,如果全局有define,那么就会用require.js的define方法去定义,而不是直接定义到window对象上,所以katex就是undefined了

那么解决问题的方案就是,自己去翻vditor的源码,找打它加载的地址,然后我们自己去加载,然后赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
try {
const vditorDepdencePrefix = 'vditor-dep';
const vditorDepdence = {
[`${vditorDepdencePrefix}.katex`]: `${cdn}/dist/js/katex/katex.min.js?v=0.16.9`,
[`${vditorDepdencePrefix}.ABCJS`]: `${cdn}/dist/js/abcjs/abcjs_basic.min`,
[`${vditorDepdencePrefix}.plantumlEncoder`]: `${cdn}/dist/js/plantuml/plantuml-encoder.min`,
[`${vditorDepdencePrefix}.echarts`]: `${cdn}/dist/js/echarts/echarts.min`,
[`${vditorDepdencePrefix}.flowchart`]: `${cdn}/dist/js/flowchart.js/flowchart.min`,
[`${vditorDepdencePrefix}.Viz`]: `${cdn}/dist/js/graphviz/viz`,
[`${vditorDepdencePrefix}.mermaid`]: `${cdn}/dist/js/mermaid/mermaid.min`,
};
require.config({
paths: vditorDepdence,
});
Object.keys(vditorDepdence).forEach((key) => {
require([key], (m) => {
window[key.split('.')[1]] = m;
});
});
} catch (e) {
console.log('initVditorDependency failed', e);
}