Skip to navigation

什么是 MDX?

¥What is MDX?

本文介绍什么是 MDX 格式。它展示了如何在 MDX 中使用 ESM 中的 markdown、JSX、JavaScript 表达式以及 importexport 语句。 有关如何将 MDX 集成到项目中的详细信息,请参阅 § 入门。当你已准备好使用 MDX 时,请参阅 § 使用 MDX

¥This article explains what the MDX format is. It shows how markdown, JSX, JavaScript expressions, and import and export statements in ESM can be used inside MDX. See § Getting started for details on how to integrate MDX into your project. See § Using MDX when you’re already all set up to use MDX.

内容

¥Contents

先决条件

¥Prerequisites

要编写和使用 MDX,你应该熟悉 Markdown(请参阅此 备忘单和教程 获取帮助)和 JavaScript(特别是 JSX)。

¥To write and enjoy MDX, you should be familiar with both markdown (see this cheat sheet and tutorial for help) and JavaScript (specifically JSX).

组件时代的 Markdown

¥Markdown for the component era

MDX 允许你在 Markdown 内容中使用 JSX。你可以导入交互式图表或警报等组件,并将它们嵌入到你的内容中。这使得使用组件编写长篇内容变得非常有趣。🚀

¥MDX allows you to use JSX in your markdown content. You can import components, such as interactive charts or alerts, and embed them within your content. This makes writing long-form content with components a blast. 🚀

更实际的是,MDX 可以解释为一种将 markdown 与 JSX 结合在一起的格式,如下所示:

¥More practically MDX can be explained as a format that combines markdown with JSX and looks as follows:

MDX
# Hello, world!

<div className="note">
  > Some notable things in a block quote!

</div>

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

¥The heading and block quote are markdown, while those HTML-like tags are JSX. Markdown often feels more natural to type than HTML or JSX for common things like emphasis or headings. JSX is an extension to JavaScript that looks like HTML but makes it convenient to use components (reusable things).

此示例在 <div> 上使用 className。那是因为它是为 React 编写的,而 React 期望类是这样的。其他框架(例如 Vue 和 Preact)期望类的定义不同,因此请注意,根据所使用的工具,JSX 的编写方式存在一些差异。

¥This example uses className on the <div>. That’s because it was written for React and React expects classes that way. Other frameworks, such as Vue and Preact, expect classes to be defined differently, so note that there are some differences in how JSX has to be authored depending on what tools it’s used with.

MDX 还支持 JavaScript 的其他一些功能:大括号 ({1 + 1}) 和 ESM(importexport)中的表达式。

¥A few other features from JavaScript are supported in MDX as well: expressions in braces ({1 + 1}) and ESM (import and export).

MDX 语法

¥MDX syntax

注意:你不必对 @mdx-js/* 包使用此语法。或者一直使用它。如果你使用打包器集成,则可以通过文件扩展名(.mdx.md)在 MDX 和 Markdown 之间进行更改。或者,可以使用 options.format

¥Note: You don’t have to use this syntax with @mdx-js/* packages. Or use it always. If you’re using a bundler integration you can change between MDX and markdown through the file extension (.mdx vs. .md). Alternatively, options.format can be used.

MDX 语法将 markdown 与 JSX 结合起来。这给了我们一些类似于文学编程的东西。它还为我们提供了两种语言的奇怪组合:markdown 对空格敏感且宽容(你输入的内容可能不完全有效,但不会崩溃),而 JavaScript 对空格不敏感且不宽容(它确实会因拼写错误而崩溃)。

¥The MDX syntax combines markdown with JSX. This gives us something along the lines of literate programming. It also gives us an odd mix of two languages: markdown is whitespace sensitive and forgiving (what you type may not exactly work but it won’t crash) whereas JavaScript is whitespace insensitive and unforgiving (it does crash on typos).

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

¥Weirdly enough we quite like how they combine!

Markdown

对于强调或标题等常见内容,Markdown 通常感觉比 HTML 或 JSX 更自然。Markdown 通常看起来更符合预期并且更简洁。而不是以下 HTML:

¥Markdown often feels more natural to type than HTML or JSX for common things like emphasis or headings. Markdown typically looks more like what’s intended and is terser. Instead of the following HTML:

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

你可以在 markdown (或 MDX)中编写等效内容,如下所示:

¥You can write the equivalent in markdown (or MDX) like so:

Markdown
> A blockquote with *some* emphasis.

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

¥MDX supports standard markdown by default (CommonMark):

Markdown
# Heading (rank 1)
## Heading 2
### 3
#### 4
##### 5
###### 6

> Block quote

* Unordered

* List

1. Ordered
2. List

A paragraph, introducing a thematic break:

---

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

a [link](https://example.com), an

![image](./image.png)

, some *emphasis*,
something **strong**, and finally a little `code()`.

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

¥Nonstandard markdown features (such as GFM, frontmatter, math, syntax highlighting) can be enabled with plugins (see ¶ Using plugins).

一些 Markdown 功能在 MDX 中不起作用:

¥Some markdown features don’t work in MDX:

  • 缩进代码在 MDX 中不起作用:

    ¥Indented code does not work in MDX:

    MDX
        console.log(1) // this is a paragraph in MDX!
    

    这样做的原因是这样你可以很好地缩进你的组件:

    ¥The reason for that is so you can nicely indent your components:

    MDX
    <main>
      <article>
        # Hello!
      </article>
    </main>
    
  • 自动链接在 MDX 中不起作用。原因是它们与 JSX 无法区分(例如:<svg:rect>),而我们更喜欢明确的。如果你需要链接,请使用完整链接:[descriptive text](https://and-the-link-here.com)

    ¥Autolinks do not work in MDX. The reason is that they can be indistinguishable from JSX (for example: <svg:rect>) and we prefer being explicit. If you want links, use full links: [descriptive text](https://and-the-link-here.com)

  • HTML 语法在 MDX 中不起作用,因为它已被 JSX(<img><img />)取代。你可以使用大括号中的 JavaScript 注释来代替 HTML 注释:{/* comment! */}

    ¥HTML syntax doesn’t work in MDX as it’s replaced by JSX (<img> to <img />). Instead of HTML comments, you can use JavaScript comments in braces: {/* comment! */}

  • 未转义的左尖括号/小于 (<) 和左大括号 ({) 必须转义:<{(或使用表达式:<{`)

    ¥Unescaped left angle bracket / less than (<) and left curly brace (\{) have to be escaped: <or{(or use expressions:<, {`)

有关 MDX 与 Markdown 有何不同的更多信息,请参见 记录在这里

¥More on how MDX differs from markdown is documented here.

JSX

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

¥JSX is an extension to JavaScript that looks like HTML but makes it convenient to use components (reusable things). JSX is typically combined with a frontend framework like React, Preact, or Vue. These frameworks add support for components, which let you change repeating things like the following markup:

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

...到 JSX(或 MDX),如下所示:

¥…to JSX (or MDX) like this:

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

JSX 适合组件。它使重复的事情变得更加清晰,并允许关注点分离。MDX 支持 JSX 语法。下面的内容看起来很像 HTML:

¥JSX is good for components. It makes repeating things more clear and allows for separation of concerns. MDX supports JSX syntax. The following looks a lot like HTML:

MDX
<h1>Heading!</h1>

<abbr title="HyperText Markup Language">HTML</abbr> is a lovely language.

<section>
  And here is *markdown* in **JSX**!
</section>

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

¥But as previously mentioned you can use components too. Note that components must be defined. You can import them, define them locally, or pass them in later (see § Using MDX):

MDX
<MyComponent id="123" />

You can also use objects with components, such as the `thisOne` component on
the `myComponents` object: <myComponents.thisOne />

<Component
  open
  x={1}
  label={'this is a string, *not* markdown!'}
  icon={<Icon />}
/>

有一些边缘情况 MDX 与 JSX 的不同之处

¥There are a few edge cases where MDX differs from JSX.

表达式

¥Expressions

MDX 还支持大括号内的 JavaScript 表达式:

¥MDX also supports JavaScript expressions inside curly braces:

MDX
Two 🍰 is: {Math.PI * 2}

表达式可以包含整个 JavaScript 程序,只要它们(封装在)计算结果为可渲染内容的表达式中即可。你可以像这样使用 IIFE

¥Expressions can contain whole JavaScript programs as long as they’re (wrapped in) an expression that evaluates to something that can be rendered. You can use an IIFE like so:

MDX


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

  if (guess > 0.66) {
    return <span style={{color: 'tomato'}}>Look at us.</span>
  }

  if (guess > 0.33) {
    return <span style={{color: 'violet'}}>Who would have guessed?!</span>
  }

  return <span style={{color: 'goldenrod'}}>Not me.</span>
}

)()}

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

¥Expressions can be empty or contain just a comment:

ESM

MDX 还支持 JavaScript 中的 importexport 语句。这些 ESM 功能可以在 MDX 中使用来定义事物:

¥MDX supports import and export statements from JavaScript as well. These ESM features can be used within MDX to define things:

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

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

An <External>external</External> component and a <Local>local one</Local>.

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

¥ESM can also be used for non-components (data):

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

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

交织

¥Interleaving

如果文本和标签位于同一行,则可以在 JSX 中使用 markdown“内联”,但不能使用“块”:

¥You can use markdown “inlines” but not “blocks” inside JSX if the text and tags are on the same line:

MDX
<div># this is not a heading but *this* is emphasis
</div>

一行上的文本和标签不会生成块,因此它们也不会生成 <p>。在不同的线路上,他们这样做:

¥Text and tags on one line don’t produce blocks so they don’t produce <p>s either. On separate lines, they do:

MDX
<div>
  This is a `p`.

</div>

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

¥We differentiate using this rule (same line or not). Not based on semantics of elements in HTML. So you can build incorrect HTML (which you shouldn’t):

MDX
<h1 className="main">
  Don’t do this: it’s a `p` in an `h1`
</h1>

<h1 className="main">Do this: an `h1` with `code`</h1>

如果文本和标签在同一行,但相应的开始和结束标签在不同的块中,则无法封装“块”(因此这是无效的!):

¥It’s not possible to wrap “blocks” if text and tags are on the same line but the corresponding opening and closing tags are in different blocks (so this is invalid!):

Welcome! <a href="about.html">

This is home of...

# The Falcons!</a>

要解析 markdown,我们首先必须将其划分为“块”。所以在这种情况下有两个段落和一个标题。在第一段中保留一个开始 a 标签,在标题中保留一个结束 a 标签。这会导致错误,因为它嵌套错误。

¥To parse markdown, we first have to divide it into “blocks”. So in this case two paragraphs and a heading. Leaving an opening a tag in the first paragraph and a closing a tag in the heading. Which causes an error as it is misnested.

进一步阅读

¥Further reading

MDX 中文网 - 粤ICP备13048890号