hashicorp / next-mdx-remote

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

compileMDX Frontmatter data is empty #421

Closed khanakia closed 6 months ago

khanakia commented 10 months ago

I am using this simple example from the docs and I am getting the EMPTY frontmatter data

Version: "next-mdx-remote": "^4.4.1" Framework: Next.js 14.0.3

// app/page.js
import { compileMDX } from 'next-mdx-remote/rsc'

export default async function Home() {
  // Optionally provide a type for your frontmatter object
  const { content, frontmatter } = await compileMDX<{ title: string }>({
    source: `---
      title: RSC Frontmatter Example
      ---
      # Hello World
      This is from Server Components!
    `,
    options: { parseFrontmatter: true },
  })
  return (
    <>
      <h1>{frontmatter.title}</h1>
      {content}
    </>
  )
}

Output

{
  content: {
    '$$typeof': Symbol(react.element),
    type: [Function: MDXContent],
    key: null,
    ref: null,
    props: { components: {} },
    _owner: null,
    _store: {}
  },
  frontmatter: {}
}
Yusufzai commented 10 months ago

Try the code below but not inside your page.js it should be outside of the app folder

// components/mdx-remote.js

import { MDXRemote } from 'next-mdx-remote/rsc'
import {Button} from '../app/elements/button'
import {CodeBlock} from '../app/elements/CodeBlock'

const components = {
    Button,
    CodeBlock
}

export async function CustomMDX({content}) {
  return (

    <>
    <MDXRemote
      source={content}
      components={{ ...components }}
    options={ {parseFrontmatter: true} }
    />

    </>
  )
}

and then,

Kindly below code modify as per your need

// app/post/[slug]/page.js
import { CustomMDX } from '../../../components/mdx-remote'

const getPost = async (id) => {
    const data = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
    const post = await data.json();

    return post;
  };

export const generateStaticParams = async () => {
  const data = await fetch("https://jsonplaceholder.typicode.com/posts")
  const posts = await data.json()

  return posts.map(post => ({
    params: {
      slug: post.id.toString()
    }

  }))
}

export default async function Home({ params: { slug } }) {

    const mycontent = `---
    title: RSC Frontmatter Example
    ---
    # Hello World
    <Button mycontent="some content" />
    This is from Server Components!
    <Button mycontent="some content" />
  `
  const post = await getPost(slug)

  return (
    <>

    <h1 style={{fontSize: "40px"}}>{post.title}</h1>
    <CustomMDX content={post.body} />

    </>
  )
}
philschonholzer commented 8 months ago

Had the same problem. The string literal is not allowed to have any indentation. Like this it works:

import { compileMDX } from 'next-mdx-remote/rsc'

export default async function Home() {
  // Optionally provide a type for your frontmatter object
  const {content, frontmatter} = await compileMDX<{ title: string }>({
    source: `---
title: RSC Frontmatter Example
description: "more text"
---

# Hello World
This is from Server Components!
    `,
    options: { parseFrontmatter: true },
  })

  console.log('frontmatter', frontmatter)

  return (
    <>
      <h1>{frontmatter.title}</h1>
      {content}
    </>
  )
}
talatkuyuk commented 8 months ago

I agree with @philschonholzer. The indentation in the mdx source causes the problem.

Removing the indentation like below looks a little bit ugly:

    source: `---
title: RSC Frontmatter Example
description: "more text"
---

# Hello World
This is from Server Components!
    `,

You can use dedent package in order to eleminate the indentations, and looks pretty goods.

    source: dedent`
        ---
        title: RSC Frontmatter Example
        description: "more text"
        ---

        # Hello World
        This is from Server Components!
    `,
rajks24 commented 1 month ago

the issue resolves when we pass the options . as below

const fileContents = await fs.promises.readFile(filePath, 'utf8');

      // Compile the MDX file, which will extract the frontmatter and content
      const { frontmatter, content } = await compileMDX({
        source: fileContents,
        components: mdxComponents,
        options: {
          parseFrontmatter: true,  // Ensure that frontmatter is parsed
        },
      });