Merge pull request #748 from lc-soft/fix/katex-load

Load KaTeX on demand to prevent first-paint blocking
This commit is contained in:
Jaber Jaber
2026-03-20 03:12:21 +03:00
committed by GitHub
4 changed files with 86 additions and 23 deletions
+2
View File
@@ -127,6 +127,8 @@ const WEBCHAT_HTML: &str = concat!(
"\n",
include_str!("../static/js/pages/overview.js"),
"\n",
include_str!("../static/js/katex.js"),
"\n",
include_str!("../static/js/pages/chat.js"),
"\n",
include_str!("../static/js/pages/agents.js"),
@@ -11,7 +11,4 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/contrib/auto-render.min.js"></script>
</head>
-20
View File
@@ -66,26 +66,6 @@ function renderMarkdown(text) {
return escapeHtml(text);
}
// Render LaTeX math in the chat message container using KaTeX auto-render.
// Call this after new messages are inserted into the DOM.
function renderLatex(el) {
if (typeof renderMathInElement !== 'function') return;
var target = el || document.getElementById('messages');
if (!target) return;
try {
renderMathInElement(target, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '\\[', right: '\\]', display: true },
{ left: '$', right: '$', display: false },
{ left: '\\(', right: '\\)', display: false }
],
throwOnError: false,
trust: false
});
} catch(e) { /* KaTeX render error — ignore gracefully */ }
}
function copyCode(btn) {
var code = btn.nextElementSibling;
if (code) {
+84
View File
@@ -0,0 +1,84 @@
// On-demand KaTeX loader and renderer for chat messages.
var KATEX_VERSION = '0.16.21';
var KATEX_CSS_URL = 'https://cdn.jsdelivr.net/npm/katex@' + KATEX_VERSION + '/dist/katex.min.css';
var KATEX_JS_URL = 'https://cdn.jsdelivr.net/npm/katex@' + KATEX_VERSION + '/dist/katex.min.js';
var KATEX_AUTORENDER_URL =
'https://cdn.jsdelivr.net/npm/katex@' + KATEX_VERSION + '/dist/contrib/auto-render.min.js';
var katexLoadPromise = null;
function hasLatexDelimiters(text) {
if (!text) return false;
return /\$\$|\\\[|\\\(|\$(?=\S)[^$\n]+\$/.test(text);
}
function loadScript(url) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.src = url;
script.async = true;
script.onload = function () {
resolve();
};
script.onerror = function () {
reject(new Error('Failed to load script: ' + url));
};
document.head.appendChild(script);
});
}
function ensureKatexLoaded() {
if (typeof renderMathInElement === 'function') return Promise.resolve(true);
if (katexLoadPromise) return katexLoadPromise;
katexLoadPromise = new Promise(function (resolve) {
var cssId = 'openfang-katex-css';
if (!document.getElementById(cssId)) {
var link = document.createElement('link');
link.id = cssId;
link.rel = 'stylesheet';
link.href = KATEX_CSS_URL;
document.head.appendChild(link);
}
loadScript(KATEX_JS_URL)
.then(function () {
return loadScript(KATEX_AUTORENDER_URL);
})
.then(function () {
resolve(typeof renderMathInElement === 'function');
})
.catch(function () {
katexLoadPromise = null;
resolve(false);
});
});
return katexLoadPromise;
}
// Render LaTeX math in the chat message container using KaTeX auto-render.
// Call this after new messages are inserted into the DOM.
function renderLatex(el) {
var target = el || document.getElementById('messages');
if (!target) return;
if (!hasLatexDelimiters(target.textContent || '')) return;
ensureKatexLoaded().then(function (ok) {
if (!ok || typeof renderMathInElement !== 'function') return;
try {
renderMathInElement(target, {
delimiters: [
{ left: '$$', right: '$$', display: true },
{ left: '\\[', right: '\\]', display: true },
{ left: '$', right: '$', display: false },
{ left: '\\(', right: '\\)', display: false },
],
throwOnError: false,
trust: false,
});
} catch (e) {
/* KaTeX render error — ignore gracefully */
}
});
}