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

How can I use @shikijs/rehype with react-markdown #829

Open
3 of 5 tasks
HerbertHe opened this issue Nov 8, 2024 · 3 comments
Open
3 of 5 tasks

How can I use @shikijs/rehype with react-markdown #829

HerbertHe opened this issue Nov 8, 2024 · 3 comments

Comments

@HerbertHe
Copy link

Validations

Describe the bug

I tried to use @shikijs/rehype with react-markdown, but I got an error as followed:

image

  • code:
import RehypeShiki from '@shikijs/rehype';

<ReactMarkdown
      remarkPlugins={[RemarkMath, RemarkGFM]}
      rehypePlugins={[
        RehypeKaTeX,
        [
          RehypeShiki,
          {
            themes: {
              light: 'vitesse-light',
              dark: 'vitesse-dark',
            },
          },
        ],
      ]}
      components={{}}
    >
      {content}
    </ReactMarkdown>

Reproduction

follow the document with @shikijs/rehype

Contributes

  • I am willing to submit a PR to fix this issue
  • I am willing to submit a PR with failing tests
@Serpentarius13
Copy link
Contributor

That's probably an issue with Async plugins in react-markdown: remarkjs/react-markdown#680

@liuhq
Copy link

liuhq commented Nov 8, 2024

@HerbertHe Yesterday, I also got the same issue when using shiki with react-markdown. But it seems that no a solution yet on the react-markdown side. So, I referred to this article, and I think we only need a simple hook and don't necessarily need react-markdown, like below:

Hook useRemark

import { useCallback, useState } from 'react'
import * as jsxRuntime from 'react/jsx-runtime'
import rehypeReact, { type Options as RehypeReactOptions } from 'rehype-react'
import remarkParse, { type Options as RemarkParseOptions } from 'remark-parse'
import remarkRehype, { type Options as RemarkRehypeOptions } from 'remark-rehype'
import { unified, type PluggableList } from 'unified'

export interface UseRemarkOptions {
    remarkParseOptions?: RemarkParseOptions
    remarkPlugins?: PluggableList
    remarkRehypeOptions?: RemarkRehypeOptions
    rehypePlugins?: PluggableList
    rehypeReactOptions?: Pick<RehypeReactOptions, 'components'>
    onError?: (err: Error) => void
}

export default function useRemark({
    remarkParseOptions,
    remarkPlugins = [],
    remarkRehypeOptions,
    rehypePlugins = [],
    rehypeReactOptions,
    onError = () => {},
}: UseRemarkOptions = {}): [React.ReactElement | null, (source: string) => void] {
    const [content, setContent] = useState<React.ReactElement | null>(null)

    const setMarkdown = useCallback((source: string) => {
        unified()
            .use(remarkParse, remarkParseOptions)        // parse markdown
            .use(remarkPlugins)
            .use(remarkRehype, remarkRehypeOptions)      // markdown to html
            .use(rehypePlugins)
            .use(rehypeReact, {                          // html to react elements
                ...rehypeReactOptions,
                Fragment: jsxRuntime.Fragment,
                jsx: jsxRuntime.jsx,
                jsxs: jsxRuntime.jsxs,
            } satisfies RehypeReactOptions)
            .process(source)
            .then(vfile => setContent(vfile.result))     // get react elements
            .catch(onError)
    }, [])

    return [content, setMarkdown]
}

you just need to add the pkg of unified, remark-parse, remark-rehype, rehype-react

Usage

const [markdown, setMarkdown] = useRemark({
    rehypePlugins: [
        [rehypeShiki, { theme: 'catppuccin-mocha' } satisfies RehypeShikiOptions]
    ],
})

if (markdown == null) {
    setMarkdown(source) // markdown source string
}

return <article>{markdown}</article>

Hopefully, this will be useful to you.

@HerbertHe
Copy link
Author

@liuhq Thank you for the example, maybe I don't need to do that now🌚. I just need to render the markdown formatted content for AI Agent answers. It seems that I don't need to JUST highlight the code content, but to add more interactions🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants