mdx-bundler

mdx-bundler

高效编译打包MDX文件的开源工具

mdx-bundler是一款高效的MDX文件编译打包工具,采用MDX v3和esbuild技术,具有卓越性能。它支持处理多种来源的文件,包括本地、GitHub仓库和CMS系统。该工具支持按需打包,适用于Remix和Next.js等服务端渲染框架。相比传统MDX插件,mdx-bundler突破了构建时的限制,为内容管理提供了更灵活的解决方案。

mdx-bundlerMDXesbuildReactbundlerGithub开源项目
<div align="center"> <h1>mdx-bundler 🦤</h1> <p>编译并打包你的MDX文件及其依赖项。速度飞快。</p> </div>
<!-- prettier-ignore-start -->

[![构建状态][build-badge]][build] [![代码覆盖率][coverage-badge]][coverage] [![版本][version-badge]][package] [![下载量][downloads-badge]][npmtrends] [![MIT许可证][license-badge]][license] ![所有贡献者][all-contributors-badge] [![欢迎PR][prs-badge]][prs] [![行为准则][coc-badge]][coc]

<!-- prettier-ignore-end -->

问题

你有一串MDX文本和它使用的各种TS/JS文件,你想获得这些文件的打包版本以在浏览器中执行。

解决方案

这是一个异步函数,可以编译和打包你的MDX文件及其依赖项。它使用MDX v3esbuild,因此速度非常快,并支持TypeScript文件(作为MDX文件的依赖项)。

你的源文件可以是本地的、远程GitHub仓库中的、CMS中的,或者其他任何地方,这都无关紧要。mdx-bundler只关心你传递给它所有必要的文件和源代码,它会负责为你打包所有内容。

常见问题:

<details> <summary> <strong> "MDX有什么特别之处?" </strong> </summary>

MDX允许你将简洁的markdown语法与React组件的强大功能结合起来,用于编写内容。对于内容丰富的网站,直接用HTML编写内容可能会非常繁琐。人们经常使用所见即所得编辑器来解决这个问题,但这些编辑器在将作者的意图映射到HTML时往往不尽如人意。许多人更喜欢使用markdown来表达他们的内容源,然后将其解析成HTML进行渲染。

使用Markdown编写内容的问题在于,如果你想在内容中嵌入一些交互性,你的选择会非常有限。你要么需要插入一个JavaScript目标的元素(这种方式很间接),要么可以使用iframe之类的东西。

如前所述,MDX允许你将简洁的markdown语法与React组件的强大功能结合起来。因此,你可以导入React组件并在markdown中直接渲染它。这是两全其美的解决方案。

</details> <details> <summary> <strong> "这与<a href="https://github.com/hashicorp/next-mdx-remote"><code>next-mdx-remote</code></a>有什么不同?" </strong> </summary>

mdx-bundler实际上会打包MDX文件的依赖项。例如,以下内容无法在next-mdx-remote中工作,但在mdx-bundler中可以:

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

next-mdx-remote在处理该导入时会出错,因为它只是一个编译器,而不是打包器。mdx-bundler既是MDX编译器又是打包器。这就是区别所在。

</details> <details> <summary> <strong> "这与webpack或rollup的mdx插件有什么不同?" </strong> </summary>

那些工具旨在"构建时"运行,然后你部署文件的构建版本。这意味着如果你的MDX内容中有一个拼写错误需要修改,你必须重新构建并重新部署整个网站。这也意味着你向网站添加的每个MDX页面都会增加构建时间,所以它的扩展性并不是很好。

mdx-bundler当然可以在构建时使用,但它更强大的用途是作为运行时打包器。一个常见的用例是为你的MDX内容设置一个路由,当请求到达时,你加载MDX内容并将其交给mdx-bundler进行打包。这意味着mdx-bundler具有无限的可扩展性。无论你有多少MDX内容,你的构建时间都不会变长。此外,mdx-bundler速度相当快,但为了使这种按需打包更快,你可以使用适当的缓存头来避免不必要的重新打包。

Webpack/rollup等还要求所有MDX文件都在本地文件系统上才能工作。如果你想将MDX内容存储在单独的仓库或CMS中,你就会遇到困难,或者需要在构建时进行一些复杂操作来放置文件。

使用mdx-bundler,不管你的MDX内容来自哪里,你都可以打包任何地方的文件,你只需负责将内容加载到内存中,然后将其交给mdx-bundler进行打包。

</details> <details> <summary> <strong> "这能与Remix/Gatsby/Next/CRA等一起使用吗?" </strong> </summary>

完全可以。它可以与任何这些工具一起使用。根据你的元框架是否支持服务器端渲染,你的实现方式会有所不同。你可能决定采用构建时方法(对于Gatsby/CRA),但如前所述,mdx-bundler的真正威力体现在按需打包方面。因此,它最适合Remix/Next等SSR框架。

</details> <details> <summary> <strong> "为什么用渡渡鸟emoji?🦤" </strong> </summary>

为什么不呢?

</details> <details> <summary> <strong> "为什么esbuild是一个对等依赖?" </strong> </summary>

esbuild提供了一个用GO编写的服务,它与之交互。同一时间只能运行一个这样的服务实例,并且它必须与npm包的版本相同。如果它是一个硬依赖,你将只能使用mdx-bundler使用的esbuild版本。

</details>

目录

<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->

安装

这个模块通过npm分发,它与node捆绑在一起,应该作为你项目的dependencies之一安装:

npm install --save mdx-bundler esbuild

mdx-bundler的一个依赖项需要一个可用的node-gyp设置才能正确安装。

使用

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

之后,你将code发送到客户端,然后:

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

最终,这将被渲染为(基本上):

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

选项

source

MDX的string源。

如果设置了file则不能设置此项

file

磁盘上包含MDX的文件路径。你可能还需要设置cwd

如果设置了source则不能设置此项

files

files 配置是一个包含所有要打包的文件的对象。键是文件的路径(相对于 MDX 源文件),值是文件源代码的字符串。你可以从文件系统或远程数据库获取这些内容。如果你的 MDX 不引用其他文件(或只从 node_modules 导入),则可以完全省略这个配置。

mdxOptions

这允许你修改内置的 MDX 配置(传递给 @mdx-js/esbuild)。这对于指定自己的 remarkPlugins/rehypePlugins 很有帮助。

该函数接收默认的 mdxOptions 和 frontmatter 作为参数。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

esbuildOptions

你可以使用 esbuildOptions 选项自定义任何 esbuild 选项。这需要一个函数,该函数接收默认的 esbuild 选项和 frontmatter,并期望返回一个选项对象。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

有关可用选项的更多信息,可以在 esbuild 文档 中找到。

建议使用此功能来配置 target 以达到你想要的输出,否则 esbuild 默认为 esnext,这意味着它不会编译任何标准化的特性,因此旧版浏览器的用户可能会遇到错误。

globals

这告诉 esbuild 某个模块是外部可用的。例如,如果你的 MDX 文件使用了 d3 库,而你的应用中已经在使用 d3 库,那么你最终会向用户发送两次 d3(一次用于你的应用,一次用于这个 MDX 组件)。这是浪费的,你最好告诉 esbuild 不要 打包 d3,然后在调用 getMDXComponent 时自己传递给组件。

全局外部配置选项: https://www.npmjs.com/package/@fal-works/esbuild-plugin-global-externals

这里有一个例子:

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

cwd

cwd当前工作目录)设置为一个目录将允许 esbuild 解析导入。这个目录可以是读取 mdx 内容的目录,或者是应该在其中_运行_非磁盘 mdx 的目录。

content/pages/demo.tsx

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

src/build.ts

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

grayMatterOptions

这允许你配置 gray-matter 选项

你的函数会接收当前的 gray-matter 配置,供你修改。返回你修改后的 gray matter 配置对象。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

bundleDirectory & bundlePath

这允许你设置打包输出的目录和该目录的公共 URL。如果设置了其中一个选项,另一个也必须设置。

JavaScript 包不会被写入这个目录,仍然会以字符串形式从 bundleMDX 返回。

这个功能最好与 mdxOptionsesbuildOptions 的调整一起使用。在下面的例子中,.png 文件被写入磁盘,然后从 /file/ 提供服务。

这允许你将资产与你的 MDX 一起存储,然后让 esbuild 像处理其他内容一样处理它们。

建议每个包都有自己的 bundleDirectory,这样多个包就不会覆盖彼此的资产。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

返回值

bundleMDX 返回一个 Promise,解析为具有以下属性的对象。

类型

mdx-bundler 在其自身的包中提供完整的类型定义。

bundleMDX 有一个单一的类型参数,它是你的 frontmatter 的类型。它默认为 {[key: string]: any} 并且必须是一个对象。这然后用于为返回的 frontmatter 以及传递给 esbuildOptionsmdxOptions 的 frontmatter 提供类型。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

组件替换

MDX Bundler 通过 getMDXComponent 返回的组件的 components 属性传递 MDX 替换组件的能力

这里有一个例子,它移除了图片周围的 p 标签。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

Frontmatter 和常量

你可以在 mdx 内容中引用 frontmatter 元数据或常量。

--- title: 示例文章 --- export const exampleImage = 'https://example.com/image.jpg' # {frontmatter.title} 图片替代文本

访问命名导出

你可以使用 getMDXExport 而不是 getMDXComponent 来将 mdx 文件视为模块而不仅仅是一个组件。它接受与 getMDXComponent 相同的参数。

--- title: 示例文章 --- export const toc = [{depth: 1, value: '标题'}] # 标题
[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

图片打包

通过 cwd 和 remark 插件 remark-mdx-images,你可以在你的 mdx 中打包图片!

esbuild 中有两个可以用于此目的的加载器。最简单的是 dataurl,它将图片作为内联数据 URL 输出到返回的代码中。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

file 加载器需要更多的配置才能工作。使用 file 加载器时,你的图片会被复制到输出目录,因此 esbuild 需要设置为写入文件,并且需要知道把它们放在哪里,以及在图片源中使用的文件夹的 URL。

每次调用 bundleMDX 都是相互独立的。如果你为所有内容设置相同的目录,bundleMDX 会在不警告的情况下覆盖图片。因此,每个 bundle 需要自己的输出目录。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

打包一个文件

如果你的 MDX 文件在磁盘上,你可以通过让 mdx-bundler 为你读取文件来节省一些时间和代码。不需要提供 source 字符串,你可以将 file 设置为磁盘上 MDX 的路径。将 cwd 设置为它的文件夹,这样相对导入就能正常工作。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

下游文件中的自定义组件

为了确保自定义组件在下游 MDX 文件中可访问,你可以使用 @mdx-js/react 中的 MDXProvider 将自定义组件传递给嵌套导入。

npm install --save @mdx-js/react
[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

从那里,你将 code 发送到你的客户端,然后:

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

已知问题

Cloudflare Workers

我们非常希望这能在 cloudflare workers 中工作。不幸的是,cloudflare 有两个限制阻止了 mdx-bundler 在那个环境中工作:

  1. Workers 不能运行二进制文件。bundleMDX 使用 esbuild(一个二进制文件)来打包你的 MDX 代码。
  2. Workers 不能运行 eval 或类似的东西。getMDXComponent 使用 new Function 评估打包的代码。

一个解决方法是将你的 mdx-bundler 相关代码放在不同的环境中,并从 Cloudflare worker 内部调用那个环境。在我看来,这违背了使用 Cloudflare workers 的目的。另一个潜在的解决方法是在 worker 内部使用 WASM。有 esbuild-wasm,但该包存在一些问题,这些问题在该链接中有解释。然后是 wasm-jseval,但我无法让它运行 mdx-bundler 输出的代码而不出错。

如果有人愿意深入研究这个问题,那将是非常棒的,但不幸的是,我可能永远不会去研究它。

Next.JS esbuild ENOENT

esbuild 依赖 __dirname 来确定其可执行文件的位置,Next.JS 和 Webpack 有时会破坏这一点,需要手动告诉 esbuild 去哪里查找。

bundleMDX 之前添加以下代码将直接指向你平台的正确可执行文件。

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

关于这个问题的更多信息可以在这篇文章中找到。

灵感

当我正在将 kentcdodds.com 重写为 remix 时,我决定想要保留我的博客文章为 MDX 格式,但我不想在构建时编译它们全部,或者每次修复一个拼写错误就必须重新部署。所以我制作了这个,它允许我的服务器按需编译。

其他解决方案

next-mdx-remote,但它更像是一个 mdx 编译器而不是打包器(不能为依赖项打包你的 mdx)。此外,它专注于 Next.js,而这个是与元框架无关的。

问题

想要贡献? 寻找 [Good First Issue][good-first-issue] 标签。

🐛 Bugs

请为错误、缺失的文档或意外行为提交问题。

[查看 Bugs][bugs]

💡 功能请求

请提交问题来建议新功能。通过添加 👍 来为功能请求投票。这有助于维护者确定优先处理的内容。

[查看功能请求][requests]

贡献者 ✨

感谢这些人([emoji key][emojis]):

<!-- ALL-CONTRIBUTORS-LIST:START - 请勿移除或修改此部分 --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tbody> <tr> <td align="center"><a href="https://kentcdodds.com"><img src="https://avatars.githubusercontent.com/u/1500684?v=3?s=100" width="100px;" alt="Kent C. Dodds"/><br /><sub><b>Kent C. Dodds</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=kentcdodds" title="代码">💻</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=kentcdodds" title="文档">📖</a> <a href="#infra-kentcdodds" title="基础设施(托管、构建工具等)">🚇</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=kentcdodds" title="测试">⚠️</a></td> <td align="center"><a href="https://github.com/benwis"><img src="https://avatars.githubusercontent.com/u/6953353?v=4?s=100" width="100px;" alt="benwis"/><br /><sub><b>benwis</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/issues?q=author%3Abenwis" title="Bug报告">🐛</a> <a href="https://github.com/kentcdodds/mdx-bundler/pulls?q=is%3Apr+reviewed-by%3Abenwis" title="审查拉取请求">👀</a></td> <td align="center"><a href="https://www.arcath.net"><img src="https://avatars.githubusercontent.com/u/19609?v=4?s=100" width="100px;" alt="Adam Laycock"/><br /><sub><b>Adam Laycock</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=Arcath" title="代码">💻</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=Arcath" title="测试">⚠️</a> <a href="#ideas-Arcath" title="想法、规划与反馈">🤔</a> <a href="https://github.com/kentcdodds/mdx-bundler/pulls?q=is%3Apr+reviewed-by%3AArcath" title="审查拉取请求">👀</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=Arcath" title="文档">📖</a></td> <td align="center"><a href="http://wooorm.com"><img src="https://avatars.githubusercontent.com/u/944406?v=4?s=100" width="100px;" alt="Titus"/><br /><sub><b>Titus</b></sub></a><br /><a href="#ideas-wooorm" title="想法、规划与反馈">🤔</a> <a href="https://github.com/kentcdodds/mdx-bundler/pulls?q=is%3Apr+reviewed-by%3Awooorm" title="审查拉取请求">👀</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=wooorm" title="代码">💻</a></td> <td align="center"><a href="https://github.com/ChristianMurphy"><img src="https://avatars.githubusercontent.com/u/3107513?v=4?s=100" width="100px;" alt="Christian Murphy"/><br /><sub><b>Christian Murphy</b></sub></a><br /><a href="#ideas-ChristianMurphy" title="想法、规划与反馈">🤔</a></td> <td align="center"><a href="https://ped.ro"><img src="https://avatars.githubusercontent.com/u/372831?v=4?s=100" width="100px;" alt="Pedro Duarte"/><br /><sub><b>Pedro Duarte</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=peduarte" title="文档">📖</a></td> <td align="center"><a href="https://keybase.io/erikras"><img src="https://avatars.githubusercontent.com/u/4396759?v=4?s=100" width="100px;" alt="Erik Rasmussen"/><br /><sub><b>Erik Rasmussen</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=erikras" title="文档">📖</a></td> </tr> <tr> <td align="center"><a href="https://github.com/ozyxdev"><img src="https://avatars.githubusercontent.com/u/83309085?v=4?s=100" width="100px;" alt="Omar Syx"/><br /><sub><b>Omar Syx</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/issues?q=author%3Aozyxdev" title="Bug报告">🐛</a></td> <td align="center"><a href="https://github.com/gaelhameon"><img src="https://avatars.githubusercontent.com/u/17253950?v=4?s=100" width="100px;" alt="Gaël Haméon"/><br /><sub><b>Gaël Haméon</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=gaelhameon" title="文档">📖</a></td> <td align="center"><a href="https://github.com/loiacon"><img src="https://avatars.githubusercontent.com/u/32134586?v=4?s=100" width="100px;" alt="Gabriel Loiácono"/><br /><sub><b>Gabriel Loiácono</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=loiacon" title="代码">💻</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=loiacon" title="测试">⚠️</a></td> <td align="center"><a href="https://skovy.dev"><img src="https://avatars.githubusercontent.com/u/5247455?v=4?s=100" width="100px;" alt="Spencer Miskoviak"/><br /><sub><b>Spencer Miskoviak</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=skovy" title="文档">📖</a></td> <td align="center"><a href="https://caspertheghost.me"><img src="https://avatars.githubusercontent.com/u/53900565?v=4?s=100" width="100px;" alt="Casper"/><br /><sub><b>Casper</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=Dev-CasperTheGhost" title="代码">💻</a></td> <td align="center"><a href="http://a7sc11u.dev"><img src="https://avatars.githubusercontent.com/u/803868?v=4?s=100" width="100px;" alt="Apostolos Christodoulou"/><br /><sub><b>Apostolos Christodoulou</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=a7sc11u" title="文档">📖</a></td> <td align="center"><a href="https://github.com/yordis"><img src="https://avatars.githubusercontent.com/u/4237280?v=4?s=100" width="100px;" alt="Yordis Prieto"/><br /><sub><b>Yordis Prieto</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=yordis" title="代码">💻</a></td> </tr> <tr> <td align="center"><a href="https://github.com/xoumi"><img src="https://avatars.githubusercontent.com/u/24864287?v=4?s=100" width="100px;" alt="xoumi"/><br /><sub><b>xoumi</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=xoumi" title="代码">💻</a></td> <td align="center"><a href="http://yasint.dev"><img src="https://avatars.githubusercontent.com/u/25561152?v=4?s=100" width="100px;" alt="Yasin"/><br /><sub><b>Yasin</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=yasinmiran" title="代码">💻</a></td> <td align="center"><a href="https://moweb.dev"><img src="https://avatars.githubusercontent.com/u/22095656?v=4?s=100" width="100px;" alt="Mohammed 'Mo' Mulazada"/><br /><sub><b>Mohammed 'Mo' Mulazada</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=moniac" title="文档">📖</a></td> <td align="center"><a href="https://www.canrau.com"><img src="https://avatars.githubusercontent.com/u/5196971?v=4?s=100" width="100px;" alt="Can Rau"/><br /><sub><b>Can Rau</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=CanRau" title="文档">📖</a></td> <td align="center"><a href="http://hosenur.dev"><img src="https://avatars.githubusercontent.com/u/50978981?v=4?s=100" width="100px;" alt="Hosenur Rahaman"/><br /><sub><b>Hosenur Rahaman</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=HOSENUR" title="文档">📖</a></td> <td align="center"><a href="https://macieksitkowski.com"><img src="https://avatars.githubusercontent.com/u/58401630?v=4?s=100" width="100px;" alt="Maciek Sitkowski"/><br /><sub><b>Maciek Sitkowski</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=sitek94" title="文档">📖</a></td> <td align="center"><a href="https://github.com/priyang12"><img src="https://avatars.githubusercontent.com/u/72823974?v=4?s=100" width="100px;" alt="Priyang"/><br /><sub><b>Priyang</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=priyang12" title="代码">💻</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=priyang12" title="文档">📖</a></td> </tr> <tr> <td align="center"><a href="https://github.com/theMosaad"><img src="https://avatars.githubusercontent.com/u/48773133?v=4?s=100" width="100px;" alt="Mosaad"/><br /><sub><b>Mosaad</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=theMosaad" title="文档">📖</a></td> <td align="center"><a href="https://github.com/stefanprobst"><img src="https://avatars.githubusercontent.com/u/20753323?v=4?s=100" width="100px;" alt="stefanprobst"/><br /><sub><b>stefanprobst</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=stefanprobst" title="代码">💻</a> <a href="https://github.com/kentcdodds/mdx-bundler/commits?author=stefanprobst" title="测试">⚠️</a></td> <td align="center"><a href="https://vladmoroz.com"><img src="https://avatars.githubusercontent.com/u/8441036?v=4?s=100" width="100px;" alt="Vlad Moroz"/><br /><sub><b>Vlad Moroz</b></sub></a><br /><a href="https://github.com/kentcdodds/mdx-bundler/commits?author=vladmoroz" title="代码">💻</a></td> </tr> </tbody> </table> 本项目遵循 [all-contributors] 规范。 欢迎任何形式的贡献!

许可证

MIT

编辑推荐精选

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

下拉加载更多