Skip to navigation

入门

本文介绍如何将 MDX 集成到你的项目中。 它展示了如何将 MDX 与你选择的打包器和 JSX 运行时结合使用。 要了解 MDX 格式的工作原理,我们建议你从 § 什么是 MDX 开始。 当你完成设置并准备好使用 MDX 时,请参阅 § 使用 MDX

内容

先决条件

MDX 依赖于 JSX,因此你的项目也需要支持 JSX。 任何 JSX 运行时(React、Preact、Vue 等)都可以。 请注意,我们确实为你将 JSX 编译为 JavaScript,因此你无需进行设置。

所有 @mdx-js/* 包都是用现代 JavaScript 编写的。 需要 Node.js 版本 16.0 或更高版本才能使用它们。 我们的包也是 仅限 ESM,所以它们必须是 imported 而不是 required。

注意: 使用 Rust 而不是 Node.js? 尝试 mdxjs-rs

快速开始

打包器

MDX 是一种编译为 JavaScript 的语言。 (我们还将常规 Markdown 编译为 JavaScript。)最简单的入门方法是使用打包器的集成(如果你有的话):

你还可以在没有打包程序的情况下使用 MDX:

有关这些工具的更多信息,请参阅其专用部分: ¶ Next.js¶ Node.js¶ Rollup¶ Vite¶ esbuild¶ Webpack

JSX

现在你已经设置了集成或 @mdx-js/mdx 本身,是时候配置 JSX 运行时了。

通过设置 jsxImportSourceProcessorOptions 支持其他 JSX 运行时。

有关这些工具的更多信息,请参阅其专用部分: ¶ Emotion¶ Preact¶ React¶ Solid¶ Svelte¶ 主题用户界面¶ Vue

编辑

你可以通过向编辑器添加对 MDX 的支持来增强使用 MDX 的体验:

为我们的 VS Code 扩展提供支持并用于高亮 GitHub 上的代码块的语法高亮保留在 wooorm/markdown-tm-language

类型

展开类型化导入的示例

首先安装包:

Shell
npm install @types/mdx

…TypeScript 应该会自动拾取它:

example.js
import Post from './post.mdx' // `Post` is now typed.

我们的包上打有 TypeScript。 为了使类型起作用,必须键入 JSX 命名空间。 这是通过安装和使用框架类型来完成的,例如 @types/react

要启用导入的 .mdx.md 等类型,请安装并使用 @types/mdx。 该包还导出几个有用的类型,例如代表 components 属性的 MDXComponents。 你可以像这样导入它们:

example.ts
import type {MDXComponents} from 'mdx/types.js'

安全

MDX 是一种编程语言。 如果你信任你的作者,那很好。 如果不这样做,那就不安全。

不要让互联网上的随机人员编写 MDX。 如果你这样做,你可能想考虑将 <iframe>sandbox 一起使用,但安全性很难,而且这似乎并不是 100%。 对于 Node.js,vm2 听起来很有趣。 但是你可能还应该使用 Docker 或类似工具对整个操作系统进行沙箱处理,执行限速,并确保在花费太长时间时可以终止进程。

集成

打包者

esbuild
展开示例
example.js
import mdx from '@mdx-js/esbuild'
import esbuild from 'esbuild'

await esbuild.build({
  entryPoints: ['index.mdx'],
  format: 'esm',
  outfile: 'output.js',
  plugins: [mdx({/* jsxImportSource: …, otherOptions… */})]
})

我们支持 esbuild。 安装并配置 esbuild 插件 @mdx-js/esbuild配置你的 JSX 运行时 取决于你使用哪一种(React、Preact、Vue 等)。

要使用比用户支持的更现代的 JavaScript 功能,配置 esbuild 的 target.

Rollup
展开示例
rollup.config.js
import mdx from '@mdx-js/rollup'
import {babel} from '@rollup/plugin-babel'

/** @type {import('rollup').RollupOptions} */
const config = {
  // …
  plugins: [
    // …
    mdx({/* jsxImportSource: …, otherOptions… */})
    // Babel is optional:
    babel({
      // Also run on what used to be `.mdx` (but is now JS):
      extensions: ['.js', '.jsx', '.cjs', '.mjs', '.md', '.mdx'],
      // Other options…
    })
  ]
}

export default config

我们支持 Rollup。 安装并配置 Rollup 插件 @mdx-js/rollup配置你的 JSX 运行时 取决于你使用哪一种(React、Preact、Vue 等)。

要使用比用户支持的更现代的 JavaScript 功能,安装并配置 @rollup/plugin-babel.

如果你通过它使用 Rollup,另请参阅 ¶ Vite 以获取更多信息。

Webpack
展开示例
webpack.config.js
/** @type {import('webpack').Configuration} */
const webpackConfig = {
  module: {
    // …
    rules: [
      // …
      {
        test: /\.mdx?$/,
        use: [
          // Babel is optional:
          {loader: 'babel-loader', options: {}},
          {
            loader: '@mdx-js/loader',
            /** @type {import('@mdx-js/loader').Options} */
            options: {/* jsxImportSource: …, otherOptions… */}
          }
        ]
      }
    ]
  }
}

export default webpackConfig

我们支持 webpack。 安装并配置 webpack 加载器 @mdx-js/loader配置你的 JSX 运行时 取决于你使用哪一种(React、Preact、Vue 等)。

要使用比用户支持的更现代的 JavaScript 功能,安装并配置 babel-loader.

如果你通过它使用 webpack,另请参阅 ¶ Next.js 以获取更多信息。

构建系统

Vite
展开示例
vite.config.js
import mdx from '@mdx-js/rollup'
import {defineConfig} from 'vite'

const viteConfig = defineConfig({
  plugins: [
    mdx(/* jsxImportSource: …, otherOptions… */)
  ]
})

export default viteConfig

我们支持 Vite。 安装并配置 Rollup 插件 @mdx-js/rollup配置你的 JSX 运行时 取决于你使用哪一种(React、Preact、Vue 等)。

要使用比用户支持的更现代的 JavaScript 功能,配置 Vite 的 build.target.

注意: 如果还使用 vitejs/vite-plugin-react,则必须强制 @mdx-js/rollup 在其之前的 pre 阶段运行:

vite.config.js
// …
const viteConfig = defineConfig({
  plugins: [
    {enforce: 'pre', ...mdx(/* jsxImportSource: …, otherOptions… */)},
    react()
  ]
})
// …

另请参阅 Vite 中使用的 ¶ Rollup,如果你使用它,请参阅 ¶ Vue 以获取更多信息。

编译器

Babel
扩展插件和示例使用

这个插件:

plugin.js
import path from 'node:path'
import parser from '@babel/parser'
import {compileSync} from '@mdx-js/mdx'
import estreeToBabel from 'estree-to-babel'

export function babelPluginSyntaxMdx() {
  // Tell Babel to use a different parser.
  return {parserOverride: babelParserWithMdx}
}

// A Babel parser that parses MDX files with `@mdx-js/mdx` and passes any
// other things through to the normal Babel parser.
function babelParserWithMdx(value, options) {
  if (options.sourceFileName && /\.mdx?$/.test(options.sourceFileName)) {
    // Babel does not support async parsers, unfortunately.
    return compileSync(
      {value, path: options.sourceFileName},
      // Tell `@mdx-js/mdx` to return a Babel tree instead of serialized JS.
      {recmaPlugins: [recmaBabel], /* jsxImportSource: …, otherOptions… */}
    ).result
  }

  return parser.parse(value, options)
}

// A “recma” plugin is a unified plugin that runs on the estree (used by
// `@mdx-js/mdx` and much of the JS ecosystem but not Babel).
// This plugin defines `'estree-to-babel'` as the compiler,
// which means that the resulting Babel tree is given back by `compileSync`.
function recmaBabel() {
  this.compiler = estreeToBabel
}

…可以像这样与 Babel API 一起使用:

example.js
import babel from '@babel/core'
import {babelPluginSyntaxMdx} from './plugin.js'

// Note that a filename must be set for our plugin to know it’s MDX instead of JS.
await babel.transformAsync(file, {filename: 'example.mdx', plugins: [babelPluginSyntaxMdx]})

你可能应该直接使用 Rollup 或 webpack 而不是 Babel,因为这样可以提供最好的界面。 可以在 Babel 中使用 @mdx-js/mdx,而且速度更快一些,因为如果无论如何使用 Babel,它会跳过 @mdx-js/mdx 序列化和 Babel 解析。

Babel 不支持其解析器的语法扩展(它有 “syntax” 插件,但这些插件仅打开或关闭内部标志)。 它确实支持设置不同的解析器。 这又让我们选择是使用 @mdx-js/mdx 还是 @babel/parser

站点生成器

Astro

Astro 有自己的 MDX 集成。 你可以添加与 Astro CLI 的集成: npx astro add mdx

此基本设置允许你导入 Markdown、Astro 组件和 MDX 文件作为组件。 有关如何在 MDX 文件中使用框架中的组件的信息,请参阅 Astro 的 框架组件指南

有关如何结合 Astro 和 MDX 的更多信息,请参阅 Astro 的 MDX 集成文档

Docusaurus

Docusaurus 默认支持 MDX。 有关如何将 MDX 与 Docusaurus 结合使用的信息,请参阅 Docusaurus 的 MDX 和 React 指南

Gatsby

Gatsby 有自己的插件来支持 MDX。 请参阅 gatsby-plugin-mdx 了解如何将 MDX 与 Gatsby 结合使用。

Next.js
展开示例
next.config.js
import nextMdx from '@next/mdx'

const withMdx = nextMdx({
  // By default only the `.mdx` extension is supported.
  extension: /\.mdx?$/,
  options: {/* otherOptions… */}
})

const nextConfig = withMdx({
  // Support MDX files as pages:
  pageExtensions: ['md', 'mdx', 'tsx', 'ts', 'jsx', 'js'],
})

export default nextConfig

Next.js 有自己的 MDX 集成。 安装并配置 @next/mdx

不要将 providerImportSource@mdx-js/react 与 Next 一起使用来注入组件。 请改为添加 mdx-components.tsx(在 src// 中)文件。 请参阅 nextjs.org 上配置 MDX 了解更多信息。

Parcel

Parcel 有自己的插件来支持 MDX。 请参阅 @parcel/transformer-mdx 了解如何将 MDX 与 Parcel 结合使用。

JSX 运行时

Emotion
展开示例
example.js
import {compile} from '@mdx-js/mdx'

const js = String(await compile('# hi', {jsxImportSource: '@emotion/react', /* otherOptions… */}))

jsxImportSourceProcessorOptions 设置为 '@emotion/react' 时,支持 Emotion。 你可以选择安装和配置 @mdx-js/react 以支持基于上下文的组件传递。

另请参阅 ¶ React(用于 Emotion),并参阅 ¶ Rollup¶ Webpack(你可能正在使用)以获取更多信息。

Ink
展开示例
example.mdx
# Hi!
example.js
import React from 'react'
import {Text, render} from 'ink'
import Content from './example.mdx' // Assumes an integration is used to compile MDX -> JS.

const components = {
  h1(props) {
    return React.createElement(Text, {bold: true, ...props})
  },
  p: Text
}

render(React.createElement(Content, {components}))

可与以下产品一起使用:

Shell
node --loader=@mdx-js/node-loader example.js

Ink 使用 React JSX 运行时,因此进行设置。 你需要将 HTML 元素替换为 Ink 的组件。 请参阅 § 组件表 了解它们是什么,以及 Ink 的文档了解它们可以用什么替换。

另请参阅 ¶ Node.js¶ React 了解更多信息。

Preact
展开示例
example.js
import {compile} from '@mdx-js/mdx'

const js = String(await compile('# hi', {jsxImportSource: 'preact', /* otherOptions… */}))

jsxImportSourceProcessorOptions 设置为 'preact' 时支持 Preact。 你可以选择安装和配置 @mdx-js/preact 以支持基于上下文的组件传递。

另请参阅你可能正在使用的 ¶ Rollup¶ esbuild¶ Webpack,了解更多信息。

React

默认支持 React。 你可以选择安装和配置 @mdx-js/react 以支持基于上下文的组件传递。

另请参阅你可能正在使用的 ¶ Rollup¶ esbuild¶ Webpack,了解更多信息。

主题界面
展开示例

不带 @mdx-js/react 的示例

example.js
import {base} from '@theme-ui/preset-base'
import {ThemeProvider, components} from 'theme-ui'
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

<ThemeProvider theme={base}>
  <Post components={components} />
</ThemeProvider>

带有 @mdx-js/react 的示例

example.js
import {base} from '@theme-ui/preset-base'
import {ThemeProvider} from 'theme-ui'
import Post from './post.mdx' // Assumes an integration is used to compile MDX -> JS.

<ThemeProvider theme={base}>
  <Post />
</ThemeProvider>

主题界面 是一个特定于 React 的库,它依赖于上下文来访问其有效组件。 你可以安装和配置 @mdx-js/react 以支持基于上下文的组件传递。

另请参阅你可能正在使用的 ¶ Emotion¶ React¶ Rollup¶ esbuild¶ Webpack,了解更多信息。

Svelte
展开示例
example.js
import {compile} from '@mdx-js/mdx'

const js = String(await compile('# hi', {jsxImportSource: 'svelte-jsx', /* otherOptions… */}))

jsxImportSourceProcessorOptions 设置为 'svelte-jsx' 时,支持 Svelte。

另请参阅你可能正在使用的 ¶ Rollup¶ esbuild¶ Webpack,了解更多信息。

Vue
展开示例
example.js
import {compile} from '@mdx-js/mdx'

const js = String(await compile('# hi', {jsxImportSource: 'vue', /* otherOptions… */}))

jsxImportSourceProcessorOptions 设置为 'vue' 时,支持 Vue。 你可以选择安装和配置 @mdx-js/vue 以支持基于上下文的组件传递。

另请参阅你可能正在使用的 ¶ Vite 以获取更多信息。

Solid
展开示例
example.js
import {compile} from '@mdx-js/mdx'

const js = String(await compile('# hi', {jsxImportSource: 'solid-js/h', /* otherOptions… */}))

jsxImportSourceProcessorOptions 设置为 'solid-js/h' 时支持实心。

另请参阅你可能正在使用的 ¶ Rollup¶ Vite 以获取更多信息。

JavaScript 引擎

Node.js

可以使用 @mdx-js/node-loader.MDX 文件导入 Node 中。 有关如何配置它的信息,请参阅其自述文件。

进一步阅读

MDX 中文网 - 粤ICP备13048890号