Skip to content
MDX logo
v1.6.16

入门

如果你现有的项目需要集成 MDX,请查看针对特定框架的 安装指南。

目录

Hello World

以下是一个最小可运行的 MDX 示例:

# Hello, world!

上述示例在页面上显示一个 “Hello, world!” 标题。 你也可以这样写:

<h1>Hello, world!</h1>

这样显示相同的标题。

MDX 语法

MDX 语法可以简化 Markdown 中集成 JSX 的复杂度。 MDX 语法时 Markdown 语法的超集,并且还支持导入(import)、导出(export)和 JSX。

Markdown

传统上,Markdown 用于生成 HTML。 许多开发人员都喜欢用 Markdown 书写,因为这通常看起来 更符合预期,并且通常更简洁。 例如,如下 HTML:

<blockquote>
<p>A blockquote with <em>some</em> emphasis.</p>
</blockquote>

可以用 Markdown (或 MDX)书写为等价形式:

> A blockquote with _some_ emphasis.

Markdown 对 内容 友好。 MDX 支持标准的 Markdown 语法。 了解 Markdown 时学习 MDX 的重要前提条件。推荐学习资料: Markdown 指南中文版

JSX

最近,越来越多的开发人员开始用 JSX 来生成 HTML 标签了。 JSX 同城与诸如 React 或 Vue 的前端框架结合在一起使用。 这些框架增加了对组件的支持,使你可以简化重复性劳动, 例如以下内容:

<h2>Hello, Venus!</h2>
<h2>Hello, Mars!</h2>

用 JSX (或 MDX) 可书写为:

<Welcome name="Venus" />
<Welcome name="Mars" />

JSX 对 组件 非常友好。 它简化了重复性劳动,并分离关注点(separation of concerns)。 MDX 完全支持 JSX 语法。 任何以 < 字符开头的行都将被视为 JSX 代码块。

MDX

我么都喜欢 HTML,但是我们仍然创建了 MDX,将 Markdown 的优点 和 JSX 的优点结合起来。 以下示例展示了如何将它们组合在一起。The following example shows how they can be combined. 这个示例是交互式的,代码可以编辑!

MDX 支持两外两个功能: importsexports.

导入(Imports)

import (ES2015) 可用于导入(import)组件、数据和 文档。

导入(import)组件

你可以导入(import)组件,例如导入你自己的或 rebass 的组件,如下所示:

import { Box, Heading, Text } from 'rebass'
# Here is a JSX block
It is using imported components!
<Box>
<Heading>Here's a JSX block</Heading>
<Text>It's pretty neat</Text>
</Box>
导入(import)数据

你还可以导入需要显示的数据:

import snowfallData from './snowfall.json'
import BarChart from './charts/BarChart'
# Recent snowfall trends
2019 has been a particularly snowy year when compared to the last decade.
<BarChart data={snowfallData} />
导入(import)文档

你可以将 MDX 文档嵌入其它文档中。 这也被称为 包含(transclusion)。 你可以通过导入(import) .mdx (or .md) 文件来实现:

import License from './license.md'
import Contributing from './docs/contributing.mdx'
# Hello, world!
<License />
---
<Contributing />

导出(Exports)

export (ES2015) 可用于导出(export)数据和组件。 例如,你可以导出(export)元数据(例如所用布局或 文档作者)。 这是导入(import)的 MDX 文件与当前文件之间进行互通的一种机制。

假设我们使用 webpack 和 React 导入(import)MDX 文件,如下所示:

// index.js
import React from 'react'
import MDXDocument, {metadata} from 'posts/post.mdx'
export default () => (
<>
<MDXDocument />
<footer>
<p>By: {metadata.authors.map(author => author.name).join(', ') + '.'}</p>
</footer>
</>
)

我们的 MDX 文件内容如下所示(注意 export):

// posts/post.mdx
import { sue, fred } from '../data/authors'
export const metadata = {
authors: [sue, fred]
}
# Post about MDX
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.

After bundling and evaluating, we could get something like this:

<h1>Post about MDX</h1>
<p>
MDX is a JSX in Markdown loader, parser, and renderer for ambitious projects.
</p>
<footer><p>By: Sue, Fred.</p></footer>

This is similar to what frontmatter allows in Markdown, but instead of supporting only data in something like YAML, MDX lets you use richer JavaScript structures.

通过 export 定义变量

如果需要在 MDX 文档中定义变量,则可以使用 export 来进行定义。export 不仅会导出数据,还会实例化你可以在 JSX 代码块中引用的数据:

export const myVariable = 'Yay!'
# Hello, world!
<div>{myVariable}</div>

与组件一同使用

除了以内联(inline)方式渲染组件外,你还可以传入要使用的组件, 而不是 Markdown 将要编译成的默认 HTML 元素。 这让你可以使用现有的组件,甚至使用支持 CSS-in-JS 的 styled-components 工具。

The components object is a mapping between the HTML name and the desired component you’d like to render.

// src/App.js
import React from 'react'
import Hello from '../hello.mdx'
const MyH1 = props => <h1 style={{color: 'tomato'}} {...props} />
const MyParagraph = props => <p style={{fontSize: '18px', lineHeight: 1.6}} />
const components = {
h1: MyH1,
p: MyParagraph
}
export default () => <Hello components={components} />

You can also import your components from another location like your UI library:

import React from 'react'
import Hello from '../hello.mdx'
import {Text, Heading, Code, InlineCode} from '../my-ui-library'
export default () => (
<Hello
components={{
h1: Heading,
p: Text,
code: Code,
inlineCode: InlineCode
}}
/>
)

With the above, the Heading component will be rendered for any h1, Text for p elements, and so on.

In addition to HTML elements, there is one special mapping: inlineCode can be used for code inside paragraphs, tables, etc.

See the Table of components for supported names.

MDXProvider

If you’re using an app layout that wraps your application, you can use the MDXProvider to only pass your components in one place:

// src/App.js
import React from 'react'
import {MDXProvider} from '@mdx-js/react'
import {Heading, Text, Pre, Code, Table} from './components'
const components = {
h1: Heading.H1,
h2: Heading.H2,
// …
p: Text,
code: Pre,
inlineCode: Code
}
export default props => (
<MDXProvider components={components}>
<main {...props} />
</MDXProvider>
)

This allows you to remove duplicated component passing and importing. It will typically go in layout files.

Using the wrapper

The MDXProvider has a special wrapper key that you can use in the component mapping. With your wrapper component you can set the layout of your document, inject styling, or even manipulate the children passed to the component.

// src/App.js
import React from 'react'
import {MDXProvider} from '@mdx-js/react'
const Wrapper = props => (
<main style={{padding: '20px', backgroundColor: 'tomato'}} {...props} />
)
export default ({children}) => (
<MDXProvider components={{wrapper: Wrapper}}>{children}</MDXProvider>
)

If you would like to see more advanced usage, see the wrapper customization guide.

Default exports

Sometimes from an MDX file you might want to override the wrapper. This is especially useful when you want to override layout for a single entry point at the page level. To achieve this you can use the ES default export and it will wrap your MDX document instead of the wrapper passed to MDXProvider.

You can declare a default export as a function:

import Layout from './Layout'
export default ({ children }) => <Layout some='metadata' >{children}</Layout>
# Hello, world!

Or directly as a component:

import Layout from './Layout'
export default Layout
# Hello, world!

Either works. Whatever you prefer!

组件列表

MDXProvider uses React Context to provide the component mapping internally to MDX when it renders. The following components are rendered from Markdown, so these can be keys in the component object you pass to MDXProvider.

标签名称语法
pParagraph
h1Heading 1#
h2Heading 2##
h3Heading 3###
h4Heading 4####
h5Heading 5#####
h6Heading 6######
thematicBreakThematic break***
blockquoteBlockquote>
ulList-
olOrdered list1.
liList item
tableTable
theadTable head
tbodyTable body
trTable row
td/thTable cell
prePre
codeCode```code```
emEmphasis_emphasis_
strongStrong**strong**
delDelete~~strikethrough~~
inlineCodeInlineCode`inlineCode`
hrBreak---
aLink<https://mdxjs.com> or [MDX](https://mdxjs.com)
imgImage![alt](https://mdx-logo.now.sh)

安装指南

既然我们已经了解了 MDX 的工作原理,那就开始安装它吧。

创建一个应用程序

如果你是一个想要快速创建一个应用程序并开始着手鼓捣的人, 可以使用 npm init 创建一个应用程序:

自己动手

如果上面列出的打包工具和框架不合你的口味,或者你的 用法特殊,那么你当然可以自己定做一个。 以下渲染功能是我们用于 MDX 集成测试所用的:

const babel = require('@babel/core')
const React = require('react')
const {renderToStaticMarkup} = require('react-dom/server')
const mdx = require('@mdx-js/mdx')
const {MDXProvider, mdx: createElement} = require('@mdx-js/react')
const transform = code =>
babel.transform(code, {
plugins: [
'@babel/plugin-transform-react-jsx',
'@babel/plugin-proposal-object-rest-spread'
]
}).code
const renderWithReact = async mdxCode => {
const jsx = await mdx(mdxCode, {skipExport: true})
const code = transform(jsx)
const scope = {mdx: createElement}
const fn = new Function(
'React',
...Object.keys(scope),
`${code}; return React.createElement(MDXContent)`
)
const element = fn(React, ...Object.values(scope))
const components = {
h1: ({children}) =>
React.createElement('h1', {style: {color: 'tomato'}}, children)
}
const elementWithProvider = React.createElement(
MDXProvider,
{components},
element
)
return renderToStaticMarkup(elementWithProvider)
}
Edit this page on GitHub