@fern-api/next-mdx-remote

中文文档
5.0.0发布于 2025/07/10MPL-2.0TypeScriptES Module近 30 天下载 2984

从任何远程来源装入 mdx 作为数据而不是本地导入的公用设备

中文使用文档
文档目录17 节
  1. 安装
  2. 实例
  3. 其他实例
  4. APIs 密码
  5. 替换默认组件
  6. 背景理论( Theory)
  7. 如何用这个建立博客?
  8. 洞穴
  9. 环境目标
  10. import 编号 : export
  11. 警卫
  12. 类型脚本
  13. 反应服务器组件( RSC) & Next.js app 目录支持
  14. 实例
  15. 替代品
  16. 你也许不需要 next-mdx-remote
  17. 许可证

next-mdx-remote


安装

npm install next-mdx-remote

如果使用涡轮包装,你需要添加以下 next.config.js 直至 这个问题 解决:

const nextConfig = {
+  transpilePackages: ['next-mdx-remote'],
}

实例

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

import Test from '../components/test'

const components = { Test }

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} components={components} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source = 'Some **mdx** text, with a component <Test />'
  const mdxSource = await serialize(source)
  return { props: { source: mdxSource } }
}

虽然看到这两个人在同一档案中似乎很奇怪,但这是Next.js的一件很酷的事 getStaticProps 财务报告和审定财务报表 TestPage,虽然出现在同一份文件中,但在两个不同的地方运行。 最终您的浏览器捆绑将不包括 getStaticProps 完全,或者它只在服务器上使用的任何功能,所以 serialize 将全部从浏览器捆绑中删除.

重要性: 设置任何 next-mdx-remote 编码为单独的“用途”文件。 这样做可能会对Next.js的代码分拆能力造成问题——它必须能够干净地确定仅用于服务器一侧的是什么,以及应该留在客户端捆绑中什么. 如果你放进 next-mdx-remote 代码输入一个外部的公用设施文件, 某物被打破, 删除它, 然后从上面的简单示例开始, 然后再提交一个问题 .

其他实例

解析前题

Markdown在一般情况下常被前置物配对,通常这意味着在Markdown处理方式上添加一些额外的自定义处理. 为了解决这个问题, next-mdx-remote 带有可选前题解析, 可以通过通过 parseFrontmatter: true 改为 serialize。 。 。 .

是这样的:

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

import Test from '../components/test'

const components = { Test }

export default function TestPage({ mdxSource }) {
  return (
    <div className="wrapper">
      <h1>{mdxSource.frontmatter.title}</h1>
      <MDXRemote {...mdxSource} components={components} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source = `---
title: Test
---

Some **mdx** text, with a component <Test name={frontmatter.title}/>
  `

  const mdxSource = await serialize(source, { parseFrontmatter: true })
  return { props: { mdxSource } }
}

vfile-matter 用于解析前题.

将自定义数据传递给具有“范围”的组件

<MDXRemote /> 接受一个 scope 道具,它使所有值都可用于您的 MDX .

每一键/值对 scope 参数将作为 Javascript 变量被曝光。 所以,举例来说,你可以想象 如果你有一个范围像 { foo: 'bar' },它将被解释为 const foo = 'bar'。 。 。 .

这特别意味着,你需要确保 您的密钥名称 scope 参数是有效的javascript可变名称。 举例来说,通过 { 'my-variable-name': 'bar' } 将生成一个 错误,因为密钥名称不是一个有效的javascript可变名称.

同样重要的是要指出: scope 变量必须作为 参数到组件,它们不能在正文中间显示。 下面的例子说明了这一点.

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

import Test from '../components/test'

const components = { Test }
const data = { product: 'next' }

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} components={components} scope={data} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source =
    'Some **mdx** text, with a component using a scope variable <Test product={product} />'
  const mdxSource = await serialize(source)
  return { props: { source: mdxSource } }
}
将 " 镜 " 传入 " 序列化 " 功能

您也可以将自定义数据传递到 serialize,然后将数值传递出去,并从结果中提供。 通过传播结果从 source 输入 <MDXRemote />,数据将会提供.

注意,任何范围值均转入 serialize 需要可序列,意思是无法传递函数或组件。 此外,该表所列的任何密钥 scope 参数必须是有效的javascript可变名称。 如果您需要通过不能序列的自定义范围, 您可以通过 scope 直接转到 <MDXRemote /> 在那里它被制造出来。 本节以上有这方面的例子.

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

import Test from '../components/test'

const components = { Test }
const data = { product: 'next' }

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} components={components} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source =
    'Some **mdx** text, with a component <Test product={product} />'
  const mdxSource = await serialize(source, { scope: data })
  return { props: { source: mdxSource } }
}
自定义组件来自 MDXProvider

如果想要将组件提供给任何 <MDXRemote /> 在申请中,您可以使用 <MDXProvider /> 从 @mdx-js/react。 。 。 .

// pages/_app.jsx
import { MDXProvider } from '@mdx-js/react'

import Test from '../components/test'

const components = { Test }

export default function MyApp({ Component, pageProps }) {
  return (
    <MDXProvider components={components}>
      <Component {...pageProps} />
    </MDXProvider>
  )
}
// pages/test.jsx
import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source = 'Some **mdx** text, with a component <Test />'
  const mdxSource = await serialize(source)
  return { props: { source: mdxSource } }
}
带有点的组件名称( 例如 ). motion.div(中文(简体) )

包含点的组件名称( Q).),如来自 framer-motion,可以与其他自定义组件相同,只需通过 motion 在组件对象中.

import { motion } from 'framer-motion'

import { MDXProvider } from '@mdx-js/react'
import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} components={{ motion }} />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source = `Some **mdx** text, with a component:

<motion.div animate={{ x: 100 }} />`
  const mdxSource = await serialize(source)
  return { props: { source: mdxSource } }
}
懒水化

懒水合物会推迟客户端上组件的水合. 这是一种优化技术,可以改进您的应用程序的初始负载,但可能会对您MDX内容中的任何动态内容引入意想不到的交互延迟.

注意: 这将增加一个额外的包 div 绕着你制造的MDX,这是避免 制成时水分不匹配。 。 。 .

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

import Test from '../components/test'

const components = { Test }

export default function TestPage({ source }) {
  return (
    <div className="wrapper">
      <MDXRemote {...source} components={components} lazy />
    </div>
  )
}

export async function getStaticProps() {
  // MDX text - can be from a local file, database, anywhere
  const source = 'Some **mdx** text, with a component <Test />'
  const mdxSource = await serialize(source)
  return { props: { source: mdxSource } }
}

APIs 密码

这个库揭示了一个功能和一个组件, serialize 财务报告和审定财务报表 <MDXRemote />这两人被故意隔离在他们自己的档案里 serialize 打算运行 服务器侧,所以内部 getStaticProps,它运行在服务器/构建时间. <MDXRemote /> 另一方面,它打算运行在客户端,浏览器中.

  • serialize(source: string, { mdxOptions?: object, scope?: object, parseFrontmatter?: boolean })

    serialize 消耗一串 MDX 。 也可以选择通过以下选项: 直接传递到 MDX,以及可以包含在MDX范围中的范围对象。 函数返回要传递到的对象 <MDXRemote /> 直接说.

    serialize(
      // Raw MDX contents as a string
      '# hello, world',
      // Optional parameters
      {
        // 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
        mdxOptions: {
          remarkPlugins: [],
          rehypePlugins: [],
          format: 'mdx',
        },
        // Indicates whether or not to parse the frontmatter from the MDX source
        parseFrontmatter: false,
      }
    )
    

    访问 https://mdxjs.com/packages/mdx/#编译文件-选项 备查 mdxOptions。 。 。 .

  • <MDXRemote compiledSource={string} components?={object} scope?={object} lazy?={boolean} />

    <MDXRemote /> 消耗输出 serialize 以及可选的组件参数。 它的结果可以直接转化为你的组件。 推迟水合 并立即服务 静态标记,通过 lazy 道具 (英语).

    <MDXRemote {...source} components={components} />
    

替换默认组件

渲染将使用 MDXProvider 在引擎盖下。 这意味着您可以用自定义组件来取代 HTML 标记. 这些组件列在MDXJS中 构成部分表。 。 。 .

一个实例是使用您喜欢的样式库来渲染内容 .

import { Typography } from "@material-ui/core";

const components = { Test, h2: (props) => <Typography variant="h2" {...props} /> }
...

如果您愿意, 您也可以将您的整个申请包成 <MDXProvider /> 而不是直接将组件传递到 <MDXRemote />见 实例 见上文.

说明: th/td 由于组件名中的"/"而不能工作.

背景理论( Theory)

在 Next.js app 中装入 MDX 文件的默认方式确实不妙. 之前我们写过 next-mdx-enhanced 用于将您的 MDX 文件制成布局,并导入其前题以创建索引页.

此工作流程来自 next-mdx-enhanced 不过我们取消了一些限制 next-mdx-remote数字 :

  • 文件内容必须是本地的 . 您不能将 MDX 文件存储在另一个 repo 、 数据库等中 。 对于一个足够大的操作,最终会把这些作者的内容和那些从事内容展示工作的人分开. 在同一回放中将这两个关切相重叠,使每个人的工作流程更加困难.
  • 您必须使用基于文件系统的路由 . 您的页面是根据其位置以 urls 生成的 。 或者你用 exportPathMap,这给作者造成了混淆。 无论如何,移动页面 以任何方式打破事物 - 要么页面的url 或者你的 exportPathMap 配置 .
  • 你最终会遇到表演问题. Webpack 是一个 JavaScript 捆绑器,强迫它装入上百/千页的文本内容会吹出你的内存要求. Webpack将每个页面作为一个具有大量元数据的独特对象来存储. 我们的其中一份执行书有几百页 点击超过8GB的内存 需要编辑网站。 建筑耗时超过25分钟.
  • 您在构建关系数据时将受到限制 . 将内容组织为动态的,相关的类别在您整个数据结构被前置物质解析为javascript对象并被内存所持有时是困难的.

这么说吧, next-mdx-remote 更改整个模式,以使您不是通过导入而是通过输入来加载您的 MDX 内容 getStaticProps 或者说 getServerProps - 你知道,同样的方式 你将加载其他数据。 库提供工具,以能表现的方式将MDX内容序列化并水分. 这消除了上述所有限制,并以低得多的成本这样做 -- next-mdx-enhanced 是一个非常重的图书馆 有很多自定义逻辑和 一些烦人的限制我们的非正式测试显示,建造时间减少了50%或更多.

自从这个项目最初创建以来 Kent C. Dodds 做了一个类似的项目, mdx-bundler。此库支持在 MDX 文件内导入和导出(只要您手动读取每个导入的文件并传递其内容)并自动处理前题。 如果您有许多文件, 所有导入和使用不同的组件, 您可以从使用中获取好处 mdx-bundler,作为 next-mdx-remote 目前只允许在所有页面中导入和提供组件。 需要注意的是,这个功能成本很高,尽管.. mdx-bundler其输出至少比来自 next-mdx-remote 用于基本标记下的内容.

如何用这个建立博客?

数据显示,99%的开发者工具的使用案例正在建立不必要的复杂的个人博客。 开玩笑的 但说真的,如果你想建立一个博客,供个人或小企业使用,请考虑仅仅使用普通的HTML和CSS. 你绝对不需要使用一个重的全装JavaScript框架来做一个简单的博客. 过几年你回来更新资料的时候 你会感谢自己 还没有10次被解禁.

如果你真的坚持,你看看 下个例例。 。 。

洞穴

环境目标

代码由 next-mdx-remote,用于实际使MDX目标浏览器具有模块支持. 如果您需要支持更老的浏览器,请考虑转录 compiledSource 从 serialize。 。 。 .

import 编号 : export

import 财务报告和审定财务报表 export 无法使用语句 内部 一个MDX文件。 如果您需要使用您的 MDX 文件的组件, 则应将其作为道具提供 <MDXRemote />。 。 。 .

希望这有道理,因为要工作,导入必须相对一个文件路径,这个库允许内容从任何地方加载,而不只是从设定的文件路径加载本地内容. 关于出口,MDX含量被视为数据,而不是 模块,因此我们无法获取可能从MDX中导出的任何值 next-mdx-remote。 。 。 .

警卫

这个库评价客户端的一串JavaScript,这就是它MDXRemotes MDX内容的方式. 将一个字符串评价成javascript,如果不小心进行,可能是一种危险的做法,因为它可以允许XSS攻击. 一定要确保你只通过 mdxSource a. 联合国 serialize 函数改为 <MDXRemote />,如文件指示. 不通过用户输入 <MDXRemote />。 。 。 .

如果您在您的网站上有一个 CSP 拒绝通过 eval 或者说 new Function(),您需要放宽限制,以便使用 next-mdx-remote,可以使用 unsafe-eval。 。 。 .

类型脚本

这个项目确实包括用于TypeScript的本地类型. 两者 serialize 财务报告和审定财务报表 <MDXRemote /> 拥有您所期望的正常类型,库中也会导出一个类型,您可以用该类型键入结果 getStaticProps。 。 。 .

  • MDXRemoteSerializeResult<TScope = Record<string, unknown>>: 表示返回值 serialize编辑 TScope 通用类型可以传递来表示您通过的范围数据的类型.

下面是TypeScript中简单执行的例子. 您可能不需要以这种方式对 TypeScript 的每个配置执行确切的类型 - 这个示例只是演示这些类型在需要时可以应用的地方 .

import type { GetStaticProps } from 'next'
import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote, type MDXRemoteSerializeResult } from 'next-mdx-remote'
import ExampleComponent from './example'

const components = { ExampleComponent }

interface Props {
  mdxSource: MDXRemoteSerializeResult
}

export default function ExamplePage({ mdxSource }: Props) {
  return (
    <div>
      <MDXRemote {...mdxSource} components={components} />
    </div>
  )
}

export const getStaticProps: GetStaticProps<{
  mdxSource: MDXRemoteSerializeResult
}> = async () => {
  const mdxSource = await serialize('some *mdx* content: <ExampleComponent />')
  return { props: { mdxSource } }
}

反应服务器组件( RSC) & Next.js app 目录支持

使用时间 next-mdx-remote 在服务器组件内,特别是Next.js的组件内 app 目录,通过从 next-mdx-remote/rsc. 此前,序列化和使步骤是分开的,但是向前推进RSC使得这种分离没有必要.

一些值得注意的差异:

  • <MDXRemote /> 现在接受一个 source 道具,而不是接受序列化输出 next-mdx-remote/serialize
  • 自定义组件无法再通过使用 MDXProvider 从上下文 @mdx-js/react,因为 RSC 不支持 React 背景
  • 通过时访问您 MDX 以外的前题 parseFrontmatter: true,使用 compileMdx 方法从 next-mdx-remote/rsc
  • 这个 lazy 不支持道具, 因为渲染发生在服务器上
  • <MDXRemote /> 必须在服务器上提供,因为它现在是一个Async组件。 客户端组件可以作为MDX标记的一部分提供

关于RSC的更多信息,请查看 Next.js 文档。 。 。 .

实例

假设在 Next.js 13+ 应用程序中使用 app 目录.

基础

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

// app/page.js
export default function Home() {
  return (
    <MDXRemote
      source={`# Hello World

      This is from Server Components!
      `}
    />
  )
}

装入状态

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

// app/page.js
export default function Home() {
  return (
    // Ideally this loading spinner would ensure there is no layout shift,
    // this is an example for how to provide such a loading spinner.
    // In Next.js you can also use `loading.js` for this.
    <Suspense fallback={<>Loading...</>}>
      <MDXRemote
        source={`# Hello World

        This is from Server Components!
        `}
      />
    </Suspense>
  )
}

自定义组件

// components/mdx-remote.js
import { MDXRemote } from 'next-mdx-remote/rsc'

const components = {
  h1: (props) => (
    <h1 {...props} className="large-text">
      {props.children}
    </h1>
  ),
}

export function CustomMDX(props) {
  return (
    <MDXRemote
      {...props}
      components={{ ...components, ...(props.components || {}) }}
    />
  )
}
// app/page.js
import { CustomMDX } from '../components/mdx-remote'

export default function Home() {
  return (
    <CustomMDX
      // h1 now renders with `large-text` className
      source={`# Hello World
      This is from Server Components!
    `}
    />
  )
}

MDX 外部访问前题

// 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}
    </>
  )
}

替代品

next-mdx-remote 在它所支持的特性上被评出。 如果您需要额外功能,则不由 next-mdx-remote,这里有一些可供考虑的备选方案:

你也许不需要 next-mdx-remote

如果你正在使用 React Server 组件,并且只是尝试使用带有自定义组件的基本MDX,除了核心MDX库之外,你不需要其他任何东西.

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!
<ClientComponent />
`

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 <MDXContent components={{ ClientComponent }} />
}

您也可以简化此方法 evaluate,如果计划不将编译的字符串传递到数据库或客户端组件,则在单调中编译并运行代码.

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!
<ClientComponent />

export function MDXDefinedComponent() {
  return <p>MDX-defined component</p>;
}
`

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 (
    <>
      <MDXContent components={{ ClientComponent }} />
      <MDXDefinedComponent />
    </>
  )
}

许可证

Mozilla 公共许可版本 2.0

版本与发布记录

@fern-api/next-mdx-remote 共发布 1 个版本,首次发布于 2025/07/10;过去 12 个月发布了 0 个版本。

版本发布日期距今
5.0.0latest2025/07/101.3 年前

关于 @fern-api/next-mdx-remote 的常见问题

@fern-api/next-mdx-remote 是什么?

从任何远程来源装入 mdx 作为数据而不是本地导入的公用设备

如何安装 @fern-api/next-mdx-remote?

在项目目录运行 npm install @fern-api/next-mdx-remote,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=16)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@fern-api/next-mdx-remote 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fern-api/next-mdx-remote 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@fern-api/next-mdx-remote 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=14。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@fern-api/next-mdx-remote 可以商用吗?

@fern-api/next-mdx-remote 使用 MPL-2.0 许可。弱 Copyleft:可以商用,也可以和闭源代码一起使用;但如果分发时修改了 MPL 授权的文件,这些文件的修改需以 MPL 开源。以上为概括,不构成法律意见,请以许可原文为准。

@fern-api/next-mdx-remote 的下载量有多少?

根据 npm 官方下载统计,@fern-api/next-mdx-remote 在 2026/10/15 – 2026/11/13 这 30 天内被下载 2,984 次,日均约 99 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fern-api/next-mdx-remote 还在维护吗?

最新版本 5.0.0 发布于 2025/07/10(1.3 年前);至今共发布 1 个版本,其中过去 12 个月发布了 0 个;首次发布于 2025/07/10。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。