Dynamically import MathJax (#1910)

* Dynamically import MathJax

* Only load if there's math content; cleanup

* avoid loading RSH on Math, we have MathJax for that; cleanup

* support multiline mathjax

---------

Co-authored-by: k00b <k00b@stacker.news>
This commit is contained in:
soxa 2025-02-21 22:41:27 +01:00 committed by GitHub
parent c571ba0cb7
commit bc3c008a6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -20,7 +20,6 @@ import rehypeSN from '@/lib/rehype-sn'
import remarkUnicode from '@/lib/remark-unicode' import remarkUnicode from '@/lib/remark-unicode'
import Embed from './embed' import Embed from './embed'
import remarkMath from 'remark-math' import remarkMath from 'remark-math'
import rehypeMathjax from 'rehype-mathjax'
const rehypeSNStyled = () => rehypeSN({ const rehypeSNStyled = () => rehypeSN({
stylers: [{ stylers: [{
@ -35,7 +34,6 @@ const rehypeSNStyled = () => rehypeSN({
}) })
const remarkPlugins = [gfm, remarkUnicode, [remarkMath, { singleDollarTextMath: false }]] const remarkPlugins = [gfm, remarkUnicode, [remarkMath, { singleDollarTextMath: false }]]
const rehypePlugins = [rehypeSNStyled, rehypeMathjax]
export function SearchText ({ text }) { export function SearchText ({ text }) {
return ( return (
@ -55,6 +53,19 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child
const router = useRouter() const router = useRouter()
const [show, setShow] = useState(false) const [show, setShow] = useState(false)
const containerRef = useRef(null) const containerRef = useRef(null)
const [mathJaxPlugin, setMathJaxPlugin] = useState(null)
// we only need mathjax if there's math content between $$ tags
useEffect(() => {
if (/\$\$(.|\n)+\$\$/g.test(children)) {
import('rehype-mathjax').then(mod => {
setMathJaxPlugin(() => mod.default)
}).catch(err => {
console.error('error loading mathjax', err)
setMathJaxPlugin(null)
})
}
}, [children])
// if we are navigating to a hash, show the full text // if we are navigating to a hash, show the full text
useEffect(() => { useEffect(() => {
@ -133,12 +144,12 @@ export default memo(function Text ({ rel = UNKNOWN_LINK_REL, imgproxyUrls, child
<ReactMarkdown <ReactMarkdown
components={components} components={components}
remarkPlugins={remarkPlugins} remarkPlugins={remarkPlugins}
rehypePlugins={rehypePlugins} rehypePlugins={[rehypeSNStyled, mathJaxPlugin].filter(Boolean)}
remarkRehypeOptions={{ clobberPrefix: `itemfn-${itemId}-` }} remarkRehypeOptions={{ clobberPrefix: `itemfn-${itemId}-` }}
> >
{children} {children}
</ReactMarkdown> </ReactMarkdown>
), [components, remarkPlugins, rehypePlugins, children, itemId]) ), [components, remarkPlugins, mathJaxPlugin, children, itemId])
const showOverflow = useCallback(() => setShow(true), [setShow]) const showOverflow = useCallback(() => setShow(true), [setShow])
@ -230,6 +241,7 @@ function Table ({ node, ...props }) {
function Code ({ node, inline, className, children, style, ...props }) { function Code ({ node, inline, className, children, style, ...props }) {
const [ReactSyntaxHighlighter, setReactSyntaxHighlighter] = useState(null) const [ReactSyntaxHighlighter, setReactSyntaxHighlighter] = useState(null)
const [syntaxTheme, setSyntaxTheme] = useState(null) const [syntaxTheme, setSyntaxTheme] = useState(null)
const language = className?.match(/language-(\w+)/)?.[1] || 'text'
const loadHighlighter = useCallback(() => const loadHighlighter = useCallback(() =>
Promise.all([ Promise.all([
@ -239,7 +251,7 @@ function Code ({ node, inline, className, children, style, ...props }) {
) )
useEffect(() => { useEffect(() => {
if (!inline) { if (!inline && language !== 'math') { // MathJax should handle math
// loading the syntax highlighter and theme only when needed // loading the syntax highlighter and theme only when needed
loadHighlighter().then(([highlighter, theme]) => { loadHighlighter().then(([highlighter, theme]) => {
setReactSyntaxHighlighter(() => highlighter) setReactSyntaxHighlighter(() => highlighter)
@ -256,8 +268,6 @@ function Code ({ node, inline, className, children, style, ...props }) {
) )
} }
const language = className?.match(/language-(\w+)/)?.[1] || 'text'
return ( return (
<ReactSyntaxHighlighter style={syntaxTheme} language={language} PreTag='div' customStyle={{ borderRadius: '0.3rem' }} {...props}> <ReactSyntaxHighlighter style={syntaxTheme} language={language} PreTag='div' customStyle={{ borderRadius: '0.3rem' }} {...props}>
{children} {children}