跳转到导航
3-4 分钟阅读
作者:John Otander, Titus Wormer

什么是 MDX?

本文解释了 MDX 格式是什么。 它展示了如何在 MDX 中使用 Markdown、JSX、JavaScript 表达式,以及 ESM 中的 import 和 export 语句。 有关如何将 MDX 集成到你的项目中的详细信息,请参见§ 快速开始。 如果你已经配置好并准备使用 MDX,请参见§ 使用 MDX。

目录

前置条件

要编写和享受 MDX,你应该熟悉 Markdown (参见这个速查表和教程获取帮助)和 JavaScript(特别是 JSX)。

面向组件时代的 Markdown

MDX 允许你在 Markdown 内容中使用 JSX。 你可以导入组件,例如交互式图表或提示框,并将它们嵌入到内容中。 这让使用组件编写长篇内容变得非常轻松。 🚀

更具体地说,MDX 可以解释为一种将 Markdown 与 JSX 结合的格式,看起来如下:

MDX
# Hello, world!

<div className="note">
  > 引用块中的一些值得注意的内容!
</div>

标题和引用块是 Markdown,而那些类似 HTML 的标签是 JSX。 对于常见的内容如强调或标题,Markdown 通常比 HTML 或 JSX 更自然地书写。 JSX 是 JavaScript 的扩展,它看起来像 HTML,但使使用组件(可复用的东西)变得方便。

这个例子在 <div> 上使用了 className。 那是因为它是为 React 编写的,React 期望以这种方式定义类。 其他框架,如 Vue 和 Preact,期望以不同的方式定义类, 所以请注意,根据使用的工具不同,JSX 的编写方式会有一些差异。

JavaScript 的一些其他特性也在 MDX 中得到了支持:花括号中的表达式 ({1 + 1})和 ESM(import 和 export)。

MDX 语法

注意: 你不必使用 @mdx-js/* 包来使用这种语法。 也不必总是使用它。 如果你使用打包器集成,你可以通过文件扩展名(.mdx vs. .md)在 MDX 和 Markdown 之间切换。 或者,可以使用 options.format。

MDX 语法将 Markdown 与 JSX 结合。 这给我们带来了一些类似于文学编程的东西。 它也给我们带来了两种语言的奇妙混合:Markdown 是对空白敏感的和 宽容的(你输入的可能不完全有效但不会崩溃),而 JavaScript 是 对空白不敏感的和不宽容的(它会在拼写错误时崩溃)。

奇怪的是,我们非常喜欢它们的结合!

Markdown

对于常见的内容如强调或标题,Markdown 通常比 HTML 或 JSX 更自然地书写。 Markdown 通常看起来更像意图表达的内容,也更简洁。 与以下 HTML 相比:

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

你可以用 Markdown(或 MDX)这样写等价的内容:

Markdown
> A blockquote with *some* emphasis.

MDX 默认支持标准 Markdown(CommonMark):

Markdown
# 标题 (rank 1)
## 标题 2
### 3
#### 4
##### 5
###### 6

> 引用块

* 无序列表
* 列表

1. 有序列表
2. 列表

一个段落,引出一个分隔线:

---

```js
some.code()
```

一个 [链接](https://example.com),一个 ![图片](./image.png),一些*强调*,
一些**粗体**,最后是一点 `code()`。

非标准 Markdown 特性(如 GFM、frontmatter、数学公式、语法高亮)可以通过插件启用 (参见¶ 使用插件)。

一些 Markdown 特性在 MDX 中不起作用:

  • 缩进代码在 MDX 中不起作用:
    MDX
        console.log(1) // 这在 MDX 中是一个段落!
    
    原因是这样你可以优雅地缩进你的组件:
    MDX
    <main>
      <article>
        # Hello!
      </article>
    </main>
    
  • 自动链接在 MDX 中不起作用。 原因是它们可能与 JSX 无法区分(例如: <svg:rect>),我们更倾向于明确表达。 如果你想要链接,请使用完整链接: [描述文字](https://和链接地址.com)
  • HTML 语法在 MDX 中不起作用,因为它被 JSX 替代了(<img> 变为 <img />)。 你可以在花括号中使用 JavaScript 注释代替 HTML 注释: {/* comment! */}
  • 未转义的左尖括号/小于号(<)和左花括号({) 必须转义:\< 或 \{(或使用表达式:{'<'}, {'{'})

更多关于 MDX 与 Markdown 的差异请 参见此处。

JSX

JSX 是 JavaScript 的扩展,它看起来像 HTML,但使使用组件(可复用的东西)变得方便。 JSX 通常与 React、Preact 或 Vue 等前端框架结合使用。 这些框架添加了对组件的支持,让你可以改变重复的内容,如以下标记:

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

…变为这样的 JSX(或 MDX):

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

JSX 非常适合组件。 它让重复的内容更清晰,并允许关注点分离。 MDX 支持 JSX 语法。 以下内容看起来很像 HTML:

MDX
<h1>标题!</h1>

<abbr title="HyperText Markup Language">HTML</abbr> 是一门可爱的语言。

<section>
  这里是 *markdown* 在 **JSX** 中!
</section>

但如前所述,你也可以使用组件。 请注意,组件必须被定义。 你可以导入它们、在本地定义,或稍后传入(参见 § 使用 MDX):

MDX
<MyComponent id="123" />

你也可以使用带有组件的对象,例如 `myComponents` 对象上的
`thisOne` 组件:<myComponents.thisOne />

<Component
  open
  x={1}
  label={'这是一个字符串,*不是* markdown!'}
  icon={<Icon />}
/>

有一些边缘情况 MDX 与 JSX 的差异。

表达式

MDX 还支持花括号中的 JavaScript 表达式:

MDX
两个 🍰 是:{Math.PI * 2}

表达式可以包含完整的 JavaScript 程序,只要它们(被包裹在)一个可以求值为可渲染内容的表达式中。 你可以像这样使用 IIFE:

MDX
{(function () {
  const guess = Math.random()

  if (guess > 0.66) {
    return <span style={{color: 'tomato'}}>看看我们。</span>
  }

  if (guess > 0.33) {
    return <span style={{color: 'violet'}}>谁能猜到呢?!</span>
  }

  return <span style={{color: 'goldenrod'}}>不是我。</span>
})()}

表达式可以为空或只包含注释:

MDX
{/* 一个注释! */}

ESM

MDX 也支持 JavaScript 的 import 和 export 语句。 这些 ESM 特性可以在 MDX 中用于定义内容:

MDX
import {External} from './some/place.js'

export const Local = properties => <span style={{color: 'red'}} {...properties} />

一个 <External>外部</External> 组件和一个 <Local>本地</Local> 组件。

ESM 也可用于非组件(数据):

MDX
import {Chart} from './chart.js'
import population from './population.js'
export const pi = 3.14

<Chart data={population} label={'Something with ' + pi} />

交错

如果文本和标签在同一行,你可以在 JSX 中使用 Markdown "行内"内容但不能使用"块级"内容:

MDX
<div># 这不是标题但 *这个* 是强调</div>

同一行上的文本和标签不会产生块级元素,因此也不会产生 <p>。 在不同行上,它们会:

MDX
<div>
  这是一个 `p`。
</div>

我们使用以下规则来区分(是否在同一行)。 不是基于 HTML 中元素的语义。 所以你可以构建不正确的 HTML(你不应该这样做):

MDX
<h1 className="main">
  不要这样做:这是 `h1` 中的 `p`
</h1>

<h1 className="main">这样做:带 `code` 的 `h1`</h1>

如果文本和标签在同一行但对应的开始和结束标签在不同块中,则无法包裹"块级"内容 (所以这是无效的!):

欢迎! <a href="about.html">

这里是...

# The Falcons!</a>

要解析 Markdown,我们首先必须将其划分为"块"。 所以在这种情况下是两个段落和一个标题。 在第一个段落中留下一个开始的 a 标签,在标题中留下一个结束的 a 标签。 这会导致错误,因为嵌套不正确。

延伸阅读

MDX 用 ❤️ 在阿姆斯特丹、博伊西和全球各地打造
本站不会跟踪你。
MIT © 2017-2026
项目在 GitHub
网站在 GitHub
更新订阅 RSS
赞助 OpenCollective