diff --git a/README.md b/README.md
index b5c2792..306cbd2 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
# next-mdx-remote
-A set of light utilities allowing mdx to be loaded within `getStaticProps` or `getServerSideProps` and hydrated correctly on the client.
+A set of light utilities allowing MDX to be loaded within `getStaticProps` or `getServerSideProps` and hydrated correctly on the client.
-->
@@ -15,11 +15,15 @@ A set of light utilities allowing mdx to be loaded within `getStaticProps` or `g
## Installation
```sh
-# using npm
-npm i next-mdx-remote
+npm install next-mdx-remote
+```
+
+If using with Turbopack, you'll need to add the following to your `next.config.js` until [this issue](https://github.com/vercel/next.js/issues/64525) is resolved:
-# using yarn
-yarn add next-mdx-remote
+```diff
+const nextConfig = {
++ transpilePackages: ['next-mdx-remote'],
+}
```
## Examples
@@ -50,7 +54,7 @@ export async function getStaticProps() {
While it may seem strange to see these two in the same file, this is one of the cool things about Next.js -- `getStaticProps` and `TestPage`, while appearing in the same file, run in two different places. Ultimately your browser bundle will not include `getStaticProps` at all, or any of the functions it uses only on the server, so `serialize` will be removed from the browser bundle entirely.
-> **IMPORTANT**: Be very careful about putting any `mdx-remote` code into a separate "utilities" file. Doing so will likely cause issues with nextjs' code splitting abilities - it must be able to cleanly determine what is used only on the server side and what should be left in the client bundle. If you put `mdx-remote` code into an external utilities file and something is broken, remove it and start from the simple example above before filing an issue.
+> **IMPORTANT**: Be very careful about putting any `next-mdx-remote` code into a separate "utilities" file. Doing so will likely cause issues with Next.js' code splitting abilities - it must be able to cleanly determine what is used only on the server side and what should be left in the client bundle. If you put `next-mdx-remote` code into an external utilities file and something is broken, remove it and start from the simple example above before filing an issue.
### Additional Examples
@@ -290,7 +294,7 @@ This library exposes a function and a component, `serialize` and ``
- **`serialize(source: string, { mdxOptions?: object, scope?: object, parseFrontmatter?: boolean })`**
- **`serialize`** consumes a string of MDX. It can also optionally be passed options which are [passed directly to MDX](https://mdxjs.com/docs/extending-mdx/), and a scope object that can be included in the mdx scope. The function returns an object that is intended to be passed into `` directly.
+ **`serialize`** consumes a string of MDX. It can also optionally be passed options which are [passed directly to MDX](https://mdxjs.com/docs/extending-mdx/), and a scope object that can be included in the MDX scope. The function returns an object that is intended to be passed into `` directly.
```ts
serialize(
@@ -298,7 +302,7 @@ This library exposes a function and a component, `serialize` and ``
'# hello, world',
// Optional parameters
{
- // made available to the arguments of any custom mdx component
+ // made available to the arguments of any custom MDX component
scope: {},
// MDX's available options, see the MDX docs for more info.
// https://mdxjs.com/packages/mdx/#compilefile-options
@@ -307,7 +311,7 @@ This library exposes a function and a component, `serialize` and ``
rehypePlugins: [],
format: 'mdx',
},
- // Indicates whether or not to parse the frontmatter from the mdx source
+ // Indicates whether or not to parse the frontmatter from the MDX source
parseFrontmatter: false,
}
)
@@ -342,9 +346,9 @@ Note: `th/td` won't work because of the "/" in the component name.
## Background & Theory
-There isn't really a good default way to load mdx files in a Next.js app. Previously, we wrote [`next-mdx-enhanced`](https://github.com/hashicorp/next-mdx-enhanced) in order to be able to render your MDX files into layouts and import their front matter to create index pages.
+There isn't really a good default way to load MDX files in a Next.js app. Previously, we wrote [`next-mdx-enhanced`](https://github.com/hashicorp/next-mdx-enhanced) in order to be able to render your MDX files into layouts and import their front matter to create index pages.
-This workflow from mdx-enhanced was fine, but introduced a few limitations that we have removed with `next-mdx-remote`:
+This workflow from `next-mdx-enhanced` was fine, but introduced a few limitations that we have removed with `next-mdx-remote`:
- **The file content must be local.** You cannot store MDX files in another repo, a database, etc. For a large enough operation, there will end up being a split between those authoring content and those working on presentation of the content. Overlapping these two concerns in the same repo makes a more difficult workflow for everyone.
- **You are bound to filesystem-based routing.** Your pages are generated with urls according to their locations. Or maybe you remap them using `exportPathMap`, which creates confusion for authors. Regardless, moving pages around in any way breaks things -- either the page's url or your `exportPathMap` configuration.
@@ -353,13 +357,13 @@ This workflow from mdx-enhanced was fine, but introduced a few limitations that
So, `next-mdx-remote` changes the entire pattern so that you load your MDX content not through an import, but rather through `getStaticProps` or `getServerProps` -- you know, the same way you would load any other data. The library provides the tools to serialize and hydrate the MDX content in a manner that is performant. This removes all of the limitations listed above, and does so at a significantly lower cost -- `next-mdx-enhanced` is a very heavy library with a lot of custom logic and [some annoying limitations](https://github.com/hashicorp/next-mdx-enhanced/issues/17). Our informal testing has shown build times reduced by 50% or more.
-Since this project was initially created, Kent C Dodds has made a similar project, [`mdx-bundler`](https://github.com/kentcdodds/mdx-bundler). This library supports imports and exports within a mdx file (as long as you manually read each imported file and pass its contents) and automatically processes frontmatter. If you have a lot of files that all import and use different components, you may benefit from using `mdx-bundler`, as `next-mdx-remote` currently only allows components to be imported and made available across all pages. It's important to note that this functionality comes with a cost though - `mdx-bundler`'s output is at least 400% larger than the output from `next-mdx-remote` for basic markdown content.
+Since this project was initially created, Kent C. Dodds has made a similar project, [`mdx-bundler`](https://github.com/kentcdodds/mdx-bundler). This library supports imports and exports within a MDX file (as long as you manually read each imported file and pass its contents) and automatically processes frontmatter. If you have a lot of files that all import and use different components, you may benefit from using `mdx-bundler`, as `next-mdx-remote` currently only allows components to be imported and made available across all pages. It's important to note that this functionality comes with a cost though - `mdx-bundler`'s output is at least 400% larger than the output from `next-mdx-remote` for basic markdown content.
### How Can I Build A Blog With This?
-Data has shown that 99% of use cases for all developer tooling are building unnecessarily complex personal blogs. Just kidding. But seriously, if you are trying to build a blog for personal or small business use, consider just using normal html and css. You definitely do not need to be using a heavy full-stack javascript framework to make a simple blog. You'll thank yourself later when you return to make an update in a couple years and there haven't been 10 breaking releases to all of your dependencies.
+Data has shown that 99% of use cases for all developer tooling are building unnecessarily complex personal blogs. Just kidding. But seriously, if you are trying to build a blog for personal or small business use, consider just using normal HTML and CSS. You definitely do not need to be using a heavy full-stack JavaScript framework to make a simple blog. You'll thank yourself later when you return to make an update in a couple years and there haven't been 10 breaking releases to all of your dependencies.
-If you really insist though, check out [our official nextjs example implementation](https://github.com/vercel/next.js/tree/canary/examples/with-mdx-remote). 💖
+If you really insist though, check out [our official Next.js example implementation](https://github.com/vercel/next.js/tree/canary/examples/with-mdx-remote). 💖
## Caveats
@@ -388,9 +392,9 @@ This project does include native types for TypeScript use. Both `serialize` and
Below is an example of a simple implementation in TypeScript. You may not need to implement the types exactly in this way for every configuration of TypeScript - this example is just a demonstration of where the types could be applied if needed.
```tsx
-import { GetStaticProps } from 'next'
+import type { GetStaticProps } from 'next'
import { serialize } from 'next-mdx-remote/serialize'
-import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote'
+import { MDXRemote, type MDXRemoteSerializeResult } from 'next-mdx-remote'
import ExampleComponent from './example'
const components = { ExampleComponent }
@@ -417,9 +421,6 @@ export const getStaticProps: GetStaticProps<{
## React Server Components (RSC) & Next.js `app` Directory Support
-> **Warning**
-> We consider the `next-mdx-remote/rsc` API to be unstable. Use at your own discretion, and be aware that the API and behavior might change between minor and/or patch releases.
-
Usage of `next-mdx-remote` within server components, and specifically within Next.js's `app` directory, is supported by importing from `next-mdx-remote/rsc`. Previously, the serialization and render steps were separate, but going forward RSC makes this separation unnecessary.
Some noteworthy differences:
@@ -543,6 +544,88 @@ This is from Server Components!
}
```
+## Alternatives
+
+`next-mdx-remote` is opinionated in what features it supports. If you need additional features not provided by `next-mdx-remote`, here are a few alternatives to consider:
+
+- [`mdx-bundler`](https://github.com/kentcdodds/mdx-bundler)
+- [`next-mdx-remote-client`](https://github.com/ipikuka/next-mdx-remote-client)
+- [`remote-mdx`](https://github.com/devjiwonchoi/remote-mdx)
+
+### You Might Not Need `next-mdx-remote`
+
+If you're using React Server Components and just trying to use basic MDX with custom components, you don't need anything other than the core MDX library.
+
+```js
+import { compile, run } from '@mdx-js/mdx'
+import * as runtime from 'react/jsx-runtime'
+import ClientComponent from './components/client'
+
+// MDX can be retrieved from anywhere, such as a file or a database.
+const mdxSource = `# Hello, world!
+
+`
+
+export default async function Page() {
+ // Compile the MDX source code to a function body
+ const code = String(
+ await compile(mdxSource, { outputFormat: 'function-body' })
+ )
+ // You can then either run the code on the server, generating a server
+ // component, or you can pass the string to a client component for
+ // final rendering.
+
+ // Run the compiled code with the runtime and get the default export
+ const { default: MDXContent } = await run(code, {
+ ...runtime,
+ baseUrl: import.meta.url,
+ })
+
+ // Render the MDX content, supplying the ClientComponent as a component
+ return
+}
+```
+
+You can also simplify this approach with `evaluate`, which compiles and runs code in a single call if you don't plan on passing the compiled string to a database or client component.
+
+```js
+import { evaluate } from '@mdx-js/mdx'
+import * as runtime from 'react/jsx-runtime'
+import ClientComponent from './components/client'
+
+// MDX can be retrieved from anywhere, such as a file or a database.
+const mdxSource = `
+export const title = "MDX Export Demo";
+
+# Hello, world!
+
+
+export function MDXDefinedComponent() {
+ return
MDX-defined component
;
+}
+`
+
+export default async function Page() {
+ // Run the compiled code
+ const {
+ default: MDXContent,
+ MDXDefinedComponent,
+ ...rest
+ } = await evaluate(mdxSource, runtime)
+
+ console.log(rest) // logs { title: 'MDX Export Demo' }
+
+ // Render the MDX content, supplying the ClientComponent as a component, and
+ // the exported MDXDefinedComponent.
+ return (
+ <>
+
+
+ >
+ )
+}
+```
+
## License
[Mozilla Public License Version 2.0](./LICENSE)