hashicorp / next-mdx-remote

Load MDX content from anywhere
Mozilla Public License 2.0
2.51k stars 137 forks source link

Hydration failed when adding code block #387

Open desiboli opened 1 year ago

desiboli commented 1 year ago

Hi! πŸ‘‹

I'm not sure if I'm doing something wrong but I get this hydration error when I add a code block to my mdx file. Sorry if this doesn't belong here. Asking for help! Thank you πŸ™

"next": "13.4.10", "next-mdx-remote": "^4.4.1",

"Error: Hydration failed because the initial UI does not match what was rendered on the server."

My mdx file:

---
title: My First Blog
date: "18th April 2023"
description: Welcome to my first blog.
---

This is my **first** blog post using _markdown_.

### My subheading

Here is an image:

![Laptop on Desk](/laptop.jpg)

There is a code snippet below:

` ```
export function myComponent() {
  return <p>test</p>
}
` ```

<Button>Hey button</Button>

Note* I do have 3 backticks only, just not sure how I would escape three backticks when pasting my code here πŸ‘†


This is my app/blogs/[slug]/page.tsx file:

import fs from "fs"
import path from "path"
import { Suspense } from "react"
import { notFound } from "next/navigation"
import { MDXRemote } from "next-mdx-remote/rsc"
import rehypeHighlight from "rehype-highlight"

import "@/styles/highlight-js/github-dark.css"

import { getBlog } from "@/lib/api"
import { Button, type ButtonProps } from "@/components/ui/button"

const components = {
  Button: (props: ButtonProps) => <Button {...props}>{props.children}</Button>,
}

export async function generateMetadata({ params }: any) {
  const blog = getBlog(params)

  return {
    title: blog?.meta?.title,
    description: blog?.meta?.description,
    openGraph: {
      type: "article",
    },
  }
}

export async function generateStaticParams() {
  const files = fs.readdirSync(path.join("blogs"))

  const paths = files.map((filename) => ({
    slug: filename.replace(".mdx", ""),
  }))

  return paths
}

const options = {
  mdxOptions: {
    remarkPlugins: [],
    rehypePlugins: [rehypeHighlight],
  },
}

export default function Post({ params }: any) {
  const blog = getBlog(params.slug)

  if (!blog) {
    return notFound
  }

  return (
    <article className="prose prose-sm !prose-invert prose-neutral mx-auto md:prose-base lg:prose-lg">
      <h1>{blog.meta.title}</h1>

      <MDXRemote
        source={blog.content}
        components={{ ...components }}
        options={options}
      />
    </article>
  )
}
severinlandolt commented 7 months ago

Hi @desiboli did you find a solution?

talatkuyuk commented 5 months ago

@desiboli , the issue that you faced a temporary problem, I suppose. I tried your code, there is no problem. But I found some refinements in your code.

components={{ ...components }}

// will be
components={ components }

You can wrap the \ with the \ for streaming.

const options = { ... } definition would be inside the Post function which actually is expected to be async function.

But, the code above produces a page with no problem, as far as I see.