hashicorp / next-mdx-remote

Load MDX content from anywhere
Mozilla Public License 2.0
2.64k stars 140 forks source link

How to use rehype image plugins with next-mdx-remote/rsc and compileMDX? [Next13 + app directory] #356

Open timoguic opened 1 year ago

timoguic commented 1 year ago

I am trying to use compileMDX from the next-mdx-remote/rsc, and I would like to use the rehype-image-size plugin. I am using NextJS 13 with the app directory.

The relevant part of my code looks like this:

  const { content, frontmatter } = await compileMDX({
    source: fileContents,
    mdxOptions: {
      rehypePlugins: [
        [rehypeImgSize, { dir: 'public' }],
      ],
    },
    options: {
      parseFrontmatter: true
    },
    components: {
      Image,
    }
  })

The MDX is compiled, the frontmatter is accessible, but the images do not have their width/height added as expected. What am I doing wrong?

I added a minimal example set up here: https://github.com/timoguic/next-mdx-remote-rehype-example

Thanks!

Rounak-stha commented 1 year ago

hey, I do not have the answer to your question but I am also trying to use compileMdx but can't seem to find proper documentation for it. Can anyone please point me to it?

In addition to my intention to use different remark and rehype plugin, I also want to use custom components. How can I inject that with Nextjs 13 and next-mdx-remote/rsc with compileMdx ?

Rounak-stha commented 1 year ago

Turns out the compileMdx function accepts components.

rodolphoasb commented 1 year ago

I managed to make it work:

image

Here's how:

const { content, frontmatter } = await compileMDX({
    source,
    options: {
      parseFrontmatter: true,
      mdxOptions: {
        remarkPlugins: [remarkGfm]
      }
    },
    components: {
      img: (props) => (
        <Image
          src={props.src as string}
          alt={"Image"}
          width={100}
          height={100}
        />
      )
    }
  })

PS: My types in this example are far from what I would use in production! Adjust your code as needed!

riedadr commented 1 year ago

Did somebody manage to use plugins (as originally asked) with compileMDX from next-mdx-remote/rsc? I'm still trying to get it working, but it seems plugins are just ignored.

Importing normal MDX works perfectly fine with plugins. MDXRemote just seems to ignore them.

timoguic commented 1 year ago

That is exactly the issue I was trying to highlight / solve. This repository has not been updated in 7 months and the issues are not looked at. I switched to a different solution.

LouisCuvelier commented 1 year ago

I also can't make remark plugins works. Like remark-reading-time or remark-gfm

arunavo4 commented 5 months ago

I also can't make remark plugins works. Like remark-reading-time or remark-gfm

remark-gfm work only with 3.0.1

arunavo4 commented 5 months ago

Did somebody manage to use plugins (as originally asked) with compileMDX from next-mdx-remote/rsc? I'm still trying to get it working, but it seems plugins are just ignored.

Importing normal MDX works perfectly fine with plugins. MDXRemote just seems to ignore them.

Here is how I got them to work.

Note: remark-gfm only works with 3.0.1 not latest 4.0.0.


import fs from "fs/promises";
import { compileMDX } from "next-mdx-remote/rsc";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeKatex from "rehype-katex";
import rehypeSlug from "rehype-slug";
import remarkGfm from "remark-gfm";
import remarkHtml from "remark-html";
import remarkMath from "remark-math";

import { fetchDoc } from "@/app/lib/file-utils"; import { Docs } from "@/app/lib/types"; import { customMDXComponents } from "@/mdx-components"; import rehypeShiki from "@shikijs/rehype";

export default async function DocMdxPage({ params, }: { params: { component: string; slug: string }; }) { const markdown: Docs | null = await fetchDoc(params.component);

const { content } = await compileMDX({ source: markdown?.body || "", options: { parseFrontmatter: false, mdxOptions: { //@ts-expect-error ignore remarkPlugins: [remarkGfm, remarkHtml, remarkMath], rehypePlugins: [ //@ts-expect-error ignore rehypeKatex, rehypeSlug, rehypeAutolinkHeadings, [ //@ts-expect-error ignore rehypeShiki, { // or theme for a single theme themes: { light: JSON.parse( await fs.readFile( "./app/lib/themes/whiteout-color-theme.json", "utf-8" ) ), dark: JSON.parse( await fs.readFile( "./app/lib/themes/blackout-color-theme.json", "utf-8" ) ), }, defaultColor: "light", // 'light' | 'dark' | false }, ], ], }, }, components: { ...customMDXComponents }, });

return <>{content}</>; }

Another file contains the `customMDXComponents` 
```tsx
export const customMDXComponents = {
  h1: ({ className, ...props }: React.HTMLAttributes<HTMLHeadingElement>) => (
    <h1
      className={cn(
        "mt-2 scroll-m-20 leading-[3rem] text-2xl md:text-3xl lg:text-[2rem] font-bold text-grayscale-textIcon-title",
        className
      )}
      {...props}
    />
  ),
  pre: ({ className, ...props }: React.HTMLAttributes<HTMLPreElement>) => (
    <div className="relative">
      <pre
        className={cn(
          "mb-4 mt-6 max-h-[40rem] w-full whitespace-pre-wrap overflow-x-auto rounded-3xl border border-grayscale-border hover:border-grayscale-border-hover p-6 bg-white dark:bg-dark-mode-800",
          className
        )}
        {...props}
      />
      <div className="absolute top-0 right-0 p-3">
        <CopyCodeButton
          textToCopy={extractTextFromReactNodes(props.children)}
          className="z-10 w-12 h-12 p-2 border border-grayscale-border hover:border-grayscale-border-hover rounded-2xl bg-grayscale-surface backdrop-blur-xl hover:bg-grayscale-surface-hover"
        />
      </div>
    </div>
  ),
  code: ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => (
    <code className={cn("font-mono text-sm", className)} {...props} />
  ),
};

I have only shown here 3 componets but there are a lot more and all of them work as expected.