MDX not compiling when using React Component in mdx file

532 views Asked by At

I am using NextJS and MDX with next-mdx-remote to get my data and it successfully work but the only problem is whenever I try to import react components I get the following error

Error: Expected component CodeBlock to be defined: you likely forgot to import, pass, or provide it. It’s referenced in your code at 317:1-317:24

In short :

This Works -

---
title: 'First Blog Post'
author: 'Me'
publishDate: 'Nov 4th, 2023'
---

# This is our first post

Here is a regular paragraph

here is a list:

- Item one
- Item two
- Item three

## This is an h2 element

This Does Not -

---
title: 'First Blog Post'
author: 'Me'
publishDate: 'Nov 4th, 2023'
---

# This is our first post

Here is a regular paragraph

here is a list:

- Item one
- Item two
- Item three

<CodeBlock></CodeBlock>

## This is an h2 element

Below are the following files

  1. index.js for MDX

https://pastebin.com/5ZmCDtkf

  1. articles/[slug]/page.js

https://pastebin.com/X0tGqsip

  1. package.json

https://pastebin.com/iNCywNfK

Updated:

  1. mdx-components.js

https://pastebin.com/U8Bn739q

2

There are 2 answers

2
000dry On

According to next-mdx-remote documentation here:

Import and export statements can't be used inside an MDX file. If you need to use components in your MDX files, they should be provided as a prop to <MDXRemote />.

The rationale seems to be that because next-mdx-remote is intended to load content from anywhere rather than just local content, they don't support local imports directly.

0
Nathan On

I think you have a small typo in your index.js file for MDX. In your compileMDX function call, components should not have the extra curly braces around it:

const { frontmatter, content } = await compileMDX({
    source: fileContent,
    options: { parseFrontmatter: true },
    components: components // <--- remove the curly braces
})

Full code:

import fs from 'fs'
import path from 'path'
import { compileMDX } from 'next-mdx-remote/rsc'
import CodeBlock from "../../app/elements/CodeBlock";
import InfoPanel from "../../app/elements/InfoPanel";
 
const rootDirectory = path.join(process.cwd(), 'src/app', 'mdx-pages')
 
const components = {
  // Define components here
  CodeBlock,
  InfoPanel,
};
 
 
export const getPostBySlug = async slug => {
  var realSlug = slug.replace(/\.mdx$/, '')
  const filePath = path.join(rootDirectory, `${realSlug}.mdx`)
 
  const fileContent = fs.readFileSync(filePath, { encoding: 'utf8' })
 
  const { frontmatter, content } = await compileMDX({
    source: fileContent,
    options: { parseFrontmatter: true },
    components: components // <--- remove the curly braces
  })
 
  return { meta: { ...frontmatter, slug: realSlug }, content }
}
 
export const getAllPostsMeta = async () => {
  const files = fs.readdirSync(rootDirectory)
 
  let posts = []
 
  for (const file of files) {
    const { meta } = await getPostBySlug(file)
    posts.push(meta)
  }
 
  return posts
}