入门
如果你现有的项目需要集成 MDX,请查看针对特定框架的 安装指南。
Next.js 集成 MDX | Gatsby 集成 MDX | Create React App 集成 MDX | React Static 集成 MDX | Webpack 集成 MDX | Parcel 集成 MDX | Zero 集成 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 支持两外两个功能: imports 和 exports.
导入(Imports)
import
(ES2015) 可用于导入(import)组件、数据和
文档。
导入(import)组件
你可以导入(import)组件,例如导入你自己的或 rebass 的组件,如下所示:
import { Box, Heading, Text } from 'rebass'# Here is a JSX blockIt 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 trends2019 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.jsimport 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.mdximport { sue, fred } from '../data/authors'export const metadata = {authors: [sue, fred]}# Post about MDXMDX 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.jsimport 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 () => (<Hellocomponents={{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.jsimport 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.jsimport 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
.
标签 | 名称 | 语法 |
---|---|---|
p | Paragraph | |
h1 | Heading 1 | # |
h2 | Heading 2 | ## |
h3 | Heading 3 | ### |
h4 | Heading 4 | #### |
h5 | Heading 5 | ##### |
h6 | Heading 6 | ###### |
thematicBreak | Thematic break | *** |
blockquote | Blockquote | > |
ul | List | - |
ol | Ordered list | 1. |
li | List item | |
table | Table | |
thead | Table head | |
tbody | Table body | |
tr | Table row | |
td /th | Table cell | |
pre | Pre | |
code | Code | ```code``` |
em | Emphasis | _emphasis_ |
strong | Strong | **strong** |
del | Delete | ~~strikethrough~~ |
inlineCode | InlineCode | `inlineCode` |
hr | Break | --- |
a | Link | <https://mdxjs.com> or [MDX](https://mdxjs.com) |
img | Image |  |
安装指南
既然我们已经了解了 MDX 的工作原理,那就开始安装它吧。
创建一个应用程序
如果你是一个想要快速创建一个应用程序并开始着手鼓捣的人,
可以使用 npm init
创建一个应用程序:
npm init mdx
webpack
npm init mdx
parcel
npm init mdx
next
npm init mdx
create-react-app
npm init mdx
gatsby
npm init mdx
x0
npm init mdx
react-static
自己动手
如果上面列出的打包工具和框架不合你的口味,或者你的 用法特殊,那么你当然可以自己定做一个。 以下渲染功能是我们用于 MDX 集成测试所用的:
Edit this page on GitHubconst 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']}).codeconst 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)}