Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mhchem support to rehype-katex #81

Closed
4 tasks done
MrWillCom opened this issue Feb 17, 2023 · 14 comments
Closed
4 tasks done

Add mhchem support to rehype-katex #81

MrWillCom opened this issue Feb 17, 2023 · 14 comments
Labels
🙋 no/question This does not need any changes 👎 phase/no Post cannot or will not be acted on

Comments

@MrWillCom
Copy link

MrWillCom commented Feb 17, 2023

Initial checklist

Problem

I'm using LaTeX to write some docs about Chemistry, and I need mhchem to write equations easily.

Solution

However, rehype-katex is pure, and does not support \ce{} syntax by default. To use mhchem in KaTeX, I need mhchem extension, which is an official extension made by KaTeX team.

Adding <script /> into <head /> directly is not recommended, and doesn't work properly with Next.js built-in router.

Alternatives

Well, switching to rehype-mathjax works, but, #80 happens to me, too.

Related

#69 and #34 are both closed and marked as wontfix, a little bit confused, why not?

@github-actions github-actions bot added 👋 phase/new Post is being triaged automatically 🤞 phase/open Post is being triaged manually and removed 👋 phase/new Post is being triaged automatically labels Feb 17, 2023
@ChristianMurphy
Copy link
Member

ChristianMurphy commented Feb 17, 2023

They are closed because mhchem is already supported, so additional changes are not needed.
See the response from the issues you linked: #34 (comment)

An updated example looks like:

import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkMath from "remark-math";
import remarkRehype from "remark-rehype";
import rehypeKatex from "rehype-katex";
import rehypeStringify from "rehype-stringify";

import "katex/dist/contrib/mhchem";

const sourceMarkdown = `
$\\ce{a A + b B -> c \\textbf{C} + d D}$
`;

const file = await unified()
  .use(remarkParse)
  .use(remarkMath)
  .use(remarkRehype)
  .use(rehypeKatex)
  .use(rehypeStringify)
  .process(sourceMarkdown);

runnable example: https://codesandbox.io/s/katex-mhchem-wl7q64

@ChristianMurphy ChristianMurphy closed this as not planned Won't fix, can't repro, duplicate, stale Feb 17, 2023
@github-actions

This comment has been minimized.

@ChristianMurphy ChristianMurphy added the 🙋 no/question This does not need any changes label Feb 17, 2023
@github-actions github-actions bot added 👎 phase/no Post cannot or will not be acted on and removed 🤞 phase/open Post is being triaged manually labels Feb 17, 2023
@MrWillCom
Copy link
Author

Thank you so much! Excuse me, but how can I use this with Next.js?

I've tried to add katex/dist/contrib/mhchem with CDN, like this:

import Script from 'next/script'

...

<Script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/mhchem.min.js" />

However, \ce{} doesn't work and an error is thrown in the console:

screenshot of the error

Thanks again for your patience, do you have any idea with this?

@ChristianMurphy
Copy link
Member

ChristianMurphy commented Feb 17, 2023

Could you share what you are trying to do in a sandbox? Using https://next.new as a starter?
There are a bunch of different integrations with Next for different use cases, it's unclear which you are using.
Also this may be better suited as a Q&A discussion: https://github.com/orgs/remarkjs/discussions

@philipbalbas
Copy link

Hi, I have a similar issue where I'm importing mhchem to a Nextjs project but the equations aren't rendering correctly.

https://stackblitz.com/edit/nextjs-idj33f?file=pages%2Fmath.js,pages%2Findex.js,pages%2F_app.js

@ChristianMurphy
Copy link
Member

Thanks @philipbalbas!

Given that https://codesandbox.io/s/katex-mhchem-wl7q64 works in browser
I suspect there is an issue where the plugin isn't able to register in node/next

@ChristianMurphy
Copy link
Member

Taking that further, I tried to isolate the issue a bit more.
I ended up with https://stackblitz.com/edit/nextjs-xvqkxb?file=pages/index.js
It feels like next is isolating or messing with the katex context, I'm not sure, the next team may be able to offer more commentary on what next is doing. https://github.com/vercel/next.js/discussions

@philipbalbas
Copy link

Hi, thanks for taking a look. Noted on the nextjs issues.
I also suspect mdxjs not getting the context of mhchem but will have to investigate further.

@ChristianMurphy
Copy link
Member

I also suspect mdxjs not getting the context of mhchem but will have to investigate further.

That is the side effect, yes.
It doesn't necessarily get at the "why?"
Given https://codesandbox.io/s/katex-mhchem-wl7q64 and https://stackblitz.com/edit/nextjs-xvqkxb?file=pages/index.js clearly rehype-katex clearly can access the mhchem context.
With the smaller reproducible examples it's increasingly looking like it works up to the point next it added to the picture.
Which implies something next is doing is likely the root cause.

Combined with #80 it leads me to believe something about Next SSR messes with Katex and Mathjax.
Remark and MDX just happen to also be in the dependency tree, but seem to be unrelated to the issues being seen.

@edward1127
Copy link

edward1127 commented Aug 31, 2023

I'm getting the same issue to make mhchem work with nextjs. Have anyone solved the issue?

import "katex/dist/katex.min.css";
import "katex/dist/contrib/mhchem";
import rendererStyle from "@/styles/quesiton-renderer.module.scss";
import React, { useMemo } from "react";
import remarkMath from "remark-math";
import remarkGfm from "remark-gfm";
import rehypeKatex from "rehype-katex";
import ReactMarkdown from "react-markdown";
import remarkDirective from "remark-directive";
import rehypeStringify from "rehype-stringify";
import remarkDirectiveRehype from "remark-directive-rehype";
import MathField from "./Control/MathField";
import type { IQuestion } from "@/interfaces/problems";
import TextInput from "./Control/TextInput";
import Checkbox from "./Control/Checkbox";
import TextArea from "./Control/Editor";
import Editor from "./Control/Editor";
import Radio from "./Control/Radio";
import { environment } from "@/lib/environment";
import type { FormValues } from "../Form/ProblemForm";
import SketchCanvas from "./Control/SketchCanvas";
import Matching, { MatchField } from "./Control/Matching";
import CSSInJs from "./CSSInJs";
import { cn } from "@/lib/style";

function QuestionRender({
  question,
  isEditMode = false,
  className,
}: {
  question: Partial<IQuestion> | FormValues;
  isEditMode?: boolean;
  className?: string;
}) {
  const components = useMemo(() => {
    return {
      "math-input": (props: any) => (
        <MathField isEditMode={isEditMode} question={question} {...props} />
      ),
      "text-area": (props: any) => (
        <TextArea isEditMode={isEditMode} question={question} {...props} />
      ),
      "text-input": (props: any) => (
        <TextInput isEditMode={isEditMode} question={question} {...props} />
      ),
      "match-field": (props: any) => (
        <MatchField isEditMode={isEditMode} question={question} {...props} />
      ),
      matching: (props: any) => (
        <Matching isEditMode={isEditMode} question={question} {...props} />
      ),
      canvas: (props: any) => (
        <SketchCanvas isEditMode={isEditMode} question={question} {...props} />
      ),
      editor: (props: any) => (
        <Editor isEditMode={isEditMode} question={question} {...props} />
      ),
      radio: (props: any) => (
        <Radio isEditMode={isEditMode} question={question} {...props} />
      ),
      checkbox: (props: any) => (
        <Checkbox isEditMode={isEditMode} question={question} {...props} />
      ),
      p: (props: any) => <>{props.children}</>,
      img: ({ className, ...props }: { className: string; props: any }) => (
        <img
          className={`w-auto lg:max-w-[50%] max-h-96 ${
            className ? className : ""
          }`}
          {...props}
        />
      ),
      ins: ({ className, ...props }: any) => (
        <span className={cn("underline", props.className)} {...props}>
          {props.children}
        </span>
      ),
      box: (props: any) => (
        <div className={cn("border-2 border-black p-3", props.className)}>
          {props.children}
        </div>
      ),
      blank: ({ className, ...props }: any) => (
        <span
          className={cn("border-b-2 px-5 border-black", className)}
          {...props}
        >
          {props.value || props.children}
        </span>
      ),
      table: ({ className, ...props }: { className: string; props: any }) => (
        <table
          className={`table-fixed my-3 ${className ? className : ""}`}
          {...props}
        />
      ),
      td: ({
        className,
        isHeader,
        ...props
      }: {
        className: string;
        isHeader: boolean;
        props: any;
      }) => {
        return (
          <td
            className={`align-middle ${className ? className : ""}`}
            {...props}
          />
        );
      },
    };
  }, [question]);

  return (
    <>
      <ReactMarkdown
        className={cn(
          `max-w-none dynamic-tailwind prose leading-10 text-black ${rendererStyle["question-render"]}`,
          className
        )}
        remarkPlugins={[
          remarkMath,
          remarkGfm,
          remarkDirective,
          remarkDirectiveRehype,
        ]}
        rehypePlugins={[rehypeKatex, rehypeStringify]}
        components={components}
        transformImageUri={(src, alt, title) => {
          return `${environment.staticUrl}/${src}`;
        }}
      >
        {question.description}
      </ReactMarkdown>
      {isEditMode && <CSSInJs description={question.description} />}
    </>
  );
}

export default React.memo(QuestionRender);

@ChristianMurphy
Copy link
Member

Welcome @edward1127! 👋
Did you get a chance to read my message right before yours?
In particular:

Combined with #80 it leads me to believe something about Next SSR messes with Katex and Mathjax.
Remark and MDX just happen to also be in the dependency tree, but seem to be unrelated to the issues being seen.

This doesn't appear to be a remark/mdx issue, so there isn't necessarily a remark/mdx workaround to be offered.
It may be a good idea to float this question to the Next.js team (https://github.com/vercel/next.js/discussions), then cross-post the link to the Next.js discussion here so that it can be more easily found by others.

@edward1127
Copy link

Thanks. I just reposted your summary to the Next.js team vercel/next.js#54852

@edward1127
Copy link

I tried to use CSR with Next https://stackblitz.com/edit/nextjs-ftepsg?file=pages%2Findex.js, and it's still not working. I believe somehow nextjs cannot get the context of import "katex/dist/contrib/mhchem";

@edward1127
Copy link

edward1127 commented Nov 22, 2023

If explicitly import the mhchem extension, it will work for nextjs
#92

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🙋 no/question This does not need any changes 👎 phase/no Post cannot or will not be acted on
Development

No branches or pull requests

4 participants