Intro to mdx-bundler with NextJs
Tags: mdx, mdxbundler, nextjs
Published: 2021-11-04 04:53:45

---
title: Intro to mdx-bundler with NextJs
published: true
date: 2021-10-24 09:21:05 UTC
tags: mdx, mdxbundler, nextjs
canonical_url: https://www.janasundar.dev/posts/intro-to-mdx-bundler-with-nextjs
---


In this article, We'll see how to use mdx-bundler with Nextjs. MDX is the extension of markdown that allows us to write React Component inside markdown file. It helps us to make our content very interactive and dynamic. I got to know about the mdx-bundler package from Josh's blog [post](https://www.joshwcomeau.com/blog/how-i-built-my-blog/#using-mdx-with-nextjs). [Kent C Dodds](https://kentcdodds.com/) created this package. In my opinion, mdx-bundler gives Superpowers to mdx.

![superpower](https://media.graphcms.com/TcPG8vV2SWS1mdYSMZb7)

Let's have a deeper look into mdx-bundler, and I'll guide you through all the features of this package.

## Let's get started with mdx-bundler

mdx-bundler is an asynchronous function to compile and bundle our MDX files with their dependency. To compile mdx files, it uses XDM, a powerful MDX compiler with lots of features. mdx-bundler is best suited for the **SSR** framework. In this article, I'll be using NextJS.

To create a new NextJS project, run this command.

```bash
npx create-next-app@latest appname

or

yarn create next-app appname
```

Now run the following command to install mdx-bundler

```bash
npm install --save mdx-bundler esbuild

or

yarn add mdx-bundler esbuild
```

To compile and bundle our MDX files, we need to use the **bundleMDX** function in this package. It takes two parameters, the first parameter is our MDX code in a string format, and the second parameter accepts an options object.

```jsx
import {bundleMDX} from 'mdx-bundler'

const mdxSource = `

title: Example Post published: 2021-02-13 description: This is some description

* * *

# Wahoo

import Demo from './demo'

Here's a **neat** demo:

<Demo /> `.trim()

const result = await bundleMDX(mdxSource, { files: { './demo.tsx': ` import \* as React from 'react'

function Demo() { return <div>Neat demo!</div> }

export default Demo `, }, })

const {code, frontmatter} = result
```

To render the bundled MDX code, we need to import **getMDXComponent** in the client

```jsx
import * as React from 'react'

import {getMDXComponent} from 'mdx-bundler/client'

function Post({code, frontmatter}) {

const Component = React.useMemo(() => getMDXComponent(code), [code])

return ( 
<>
 <header>
  <h1>{frontmatter.title}</h1>
    <p>{frontmatter.description}</p>
 </header>
 <main>
 <Component />
 </main> 
</> ) }
```

Check out this [link](https://github.com/kentcdodds/mdx-bundler#options) to find all available options.

Most of the mdx blogs are using local mdx files to store their blog contents. In my case, I'm using GraphCMS to store the mdx data. If you don't know what GraphCMS is? [Check out my blog post](https://www.janasundar.dev/posts/how-i-built-my-blog-with-nextjs) where I explain how to get started with it.

Now we have the basic idea to use mdx-bundler. Let's breakdown down the code, and I'll guide you on how I used mdx-bundler in this blog.

```jsx
export const getStaticProps = async (context) => {

if (process.platform === 'win32') { process.env.ESBUILD_BINARY_PATH = path.join(process.cwd(), 'node_modules', 'esbuild', 'esbuild.exe'); } else { process.env.ESBUILD_BINARY_PATH = path.join(process.cwd(), 'node_modules', 'esbuild', 'bin', 'esbuild'); }

const { slug } = context.params;

const post = await getSinglePost(slug);

const result = await bundleMDX(post.content, { 
  xdmOptions(options) {
   options.rehypePlugins = [...(options.rehypePlugins ?? []), rehypeMdxCodeMeta];
   options.remarkPlugins = [...(options.remarkPlugins ?? []), gfm, emoji];
 return options;
  },
 ...(post.files ? { files: post.files } : {}),
 });

return { props: { ...result, }, }; };
```

Sometimes Nextjs don't find the exact path of esbuild. Due to this reason, We might get this **ENOENT(Error No Entry)** error. To resolve this issue, we are manually adding the executable path.

```jsx
 if (process.platform === 'win32') {
    process.env.ESBUILD_BINARY_PATH = path.join(process.cwd(), 'node_modules', 'esbuild', 'esbuild.exe');
  } else {
    process.env.ESBUILD_BINARY_PATH = path.join(process.cwd(), 'node_modules', 'esbuild', 'bin', 'esbuild');
  }
```

### Reference

- [https://www.alaycock.co.uk/2021/03/mdx-bundler#esbuild-executable](https://www.alaycock.co.uk/2021/03/mdx-bundler#esbuild-executable)

To add the custom remark and rehype plugins to our bundler, use the xdmOptions object to achieve this behavior.

```jsx
 xdmOptions(options) {
      options.rehypePlugins = [...(options.rehypePlugins ?? []), rehypeMdxCodeMeta];
      options.remarkPlugins = [...(options.remarkPlugins ?? []), gfm, emoji];
      return options;
 }
```

<Callout type="info"> Want to create a custom plugin? Check this post where [Pedro Duarte](https://ped.ro/blog/code-blocks-but-better) explained everything in detail. </Callout>

### Reference

- [https://github.com/rehypejs/rehype/blob/main/doc/plugins.md](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md)
- [https://github.com/remarkjs/remark/blob/main/doc/plugins.md](https://github.com/remarkjs/remark/blob/main/doc/plugins.md)

The main difference between mdx-bundler and other libraries are most of the library does not bundle mdx code. They also don't have the option to add the dependency to our mdx code. We can achieve this dependency import feature using both files and the CWD option. In this blog, I used files to add the dependency code.

```jsx
...(post.files ? { files: post.files } : {}),
```

I hope that you have learned how to use mdx-bundler with Nextjs. Thanks for reading ✌️ and if you enjoyed this article, share it with your friends and colleagues.

---