Skip to navigation

@mdx-js/mdx

MDX 编译器。

¥MDX compiler.

内容

¥Contents

这是什么?

¥What is this?

该包是一个将 MDX 转换为 JavaScript 的编译器。它还可以评估 MDX 代码。

¥This package is a compiler that turns MDX into JavaScript. It can also evaluate MDX code.

我什么时候应该使用这个?

¥When should I use this?

这是将 MDX 转换为 JavaScript 的核心编译器,为你提供最大的控制权。如果你使用的是打包器(Rollup、esbuild、webpack)、站点构建器(Next.js)或打包器附带的构建系统(Vite),那么最好使用集成:见 § 集成

¥This is the core compiler for turning MDX into JavaScript which gives you the most control. If you’re using a bundler (Rollup, esbuild, webpack), a site builder (Next.js), or build system (Vite) which comes with a bundler, you’re better off using an integration: see § Integrations.

安装

¥Install

这个包是 仅限 ESM。在 Node.js(版本 16+)中,使用 npm 安装:

¥This package is ESM only. In Node.js (version 16+), install with npm:

Shell
npm install @mdx-js/mdx

在 Deno 中使用 esm.sh

¥In Deno with esm.sh:

TypeScript
import {compile} from 'https://esm.sh/@mdx-js/mdx@3'

在带有 esm.sh 的浏览器中:

¥In browsers with esm.sh:

HTML
<script type="module">
  import {compile} from 'https://esm.sh/@mdx-js/mdx@3?bundle'
</script>

使用

¥Use

假设我们有一个 MDX 文档 example.mdx

¥Say we have an MDX document, example.mdx:

MDX
export function Thing() {
  return <>World!</>
}

# Hello, <Thing />

…以及 example.js 中的一些代码,用于将 example.mdx 编译为 JavaScript:

¥…and some code in example.js to compile example.mdx to JavaScript:

TypeScript
import fs from 'node:fs/promises'
import {compile} from '@mdx-js/mdx'

const compiled = await compile(await fs.readFile('example.mdx'))

console.log(String(compiled))

产量大致为:

¥Yields roughly:

TypeScript
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'

export function Thing() {
  return _jsx(_Fragment, {children: 'World!'})
}

function _createMdxContent(props) {
  const _components = {h1: 'h1', ...props.components}
  return _jsxs(_components.h1, {children: ['Hello, ', _jsx(Thing, {})]})
}

export default function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || {}
  return MDXLayout
    ? _jsx(MDXLayout, {...props, children: _jsx(_createMdxContent, {...props})})
    : _createMdxContent(props)
}

有关 MDX 如何工作以及如何使用结果的更多信息,请参阅 § 使用 MDX

¥See § Using MDX for more on how MDX work and how to use the result.

API

该包导出以下标识符:compilecompileSynccreateProcessorevaluateevaluateSyncnodeTypesrunrunSync。没有默认导出。

¥This package exports the following identifiers: compile, compileSync, createProcessor, evaluate, evaluateSync, nodeTypes, run, and runSync. There is no default export.

compile(file, options?)

将 MDX 编译为 JS。

¥Compile MDX to JS.

参数

¥Parameters

返回

¥Returns

对编译文件的 Promise(Promise<VFile>)。

¥Promise to compiled file (Promise<VFile>).

示例

¥Examples

file 的输入值可以是许多不同的值。你可以传递 UTF-8 格式的 stringUint8ArrayVFile 或任何可以提供给 new VFile 的内容。

¥The input value for file can be many different things. You can pass a string, Uint8Array in UTF-8, VFile, or anything that can be given to new VFile.

TypeScript
import {compile} from '@mdx-js/mdx'
import {VFile} from 'vfile'

await compile(':)')
await compile(Buffer.from(':-)'))
await compile({path: 'path/to/file.mdx', value: '🥳'})
await compile(new VFile({path: 'path/to/file.mdx', value: '🤭'}))

输出 VFile 可用于访问生成的代码之外的其他内容:

¥The output VFile can be used to access more than the generated code:

TypeScript
import {compile} from '@mdx-js/mdx'
import remarkPresetLintConsistent from 'remark-preset-lint-consistent' // Lint rules to check for consistent markdown.
import {reporter} from 'vfile-reporter'

const file = await compile('*like this* or _like this_?', {remarkPlugins: [remarkPresetLintConsistent]})

console.error(reporter(file))

产量:

¥Yields:

Plain text
  1:16-1:27  warning  Emphasis should use `*` as a marker  emphasis-marker  remark-lint

⚠ 1 warning

compileSync(file, options?)

同步编译 MDX 为 JS。

¥Synchronously compile MDX to JS.

如果可能,请使用异步 compile

¥When possible please use the async compile.

参数

¥Parameters

返回

¥Returns

编译文件(VFile)。

¥Compiled file (VFile).

createProcessor(options?)

创建一个处理器来将 markdown 或 MDX 编译为 JavaScript。

¥Create a processor to compile markdown or MDX to JavaScript.

注意:format: 'detect' 不允许出现在 ProcessorOptions 中。

¥Note: format: 'detect' is not allowed in ProcessorOptions.

参数

¥Parameters

返回

¥Returns

处理器 (Processorunified)。

¥Processor (Processor from unified).

evaluate(file, options)

编译run MDX。

¥Compile and run MDX.

当你信任自己的内容时,evaluate 就能发挥作用。如果可能,请使用 compile,写入文件,然后使用 Node 运行或使用 § 集成 之一。

¥When you trust your content, evaluate can work. When possible, use compile, write to a file, and then run with Node or use one of the § Integrations.

☢️ 危险:它被称为评估,因为它 eval JavaScript。

¥☢️ Danger: it’s called evaluate because it evals JavaScript.

参数

¥Parameters

返回

¥Returns

对模块的 Promise (Promise<MDXModule>mdx/types.js)。

¥Promise to a module (Promise<MDXModule> from mdx/types.js).

结果是一个对象,其中 default 字段设置为组件;导出的任何其他内容也可用。例如,假设 § 使用example.mdx 的内容在 file 中,则:

¥The result is an object with a default field set to the component; anything else that was exported is available too. For example, assuming the contents of example.mdx from § Use was in file, then:

TypeScript
import {evaluate} from '@mdx-js/mdx'
import * as runtime from 'react/jsx-runtime'

console.log(await evaluate(file, runtime))

…产量:

¥…yields:

TypeScript
{Thing: [Function: Thing], default: [Function: MDXContent]}

注意

¥Notes

编译(和运行)MDX 需要时间。

¥Compiling (and running) MDX takes time.

如果你使用基于虚拟 DOM 的框架(例如 React)实时渲染经常更改的 MDX 字符串,则性能改进的一个方法是自行调用 MDXContent 组件。原因是 evaluate 每次都会创建一个新函数,无法区分:

¥If you are live-rendering a string of MDX that often changes using a virtual DOM based framework (such as React), one performance improvement is to call the MDXContent component yourself. The reason is that the evaluate creates a new function each time, which cannot be diffed:

Diff
 const {default: MDXContent} = await evaluate('…')

-<MDXContent {...props} />
+MDXContent(props)

evaluateSync(file, options)

同步编译并运行 MDX。

¥Compile and run MDX, synchronously.

如果可能,请使用异步 evaluate

¥When possible please use the async evaluate.

☢️ 危险:它被称为评估,因为它 eval JavaScript。

¥☢️ Danger: it’s called evaluate because it evals JavaScript.

参数

¥Parameters

返回

¥Returns

模块(MDXModulemdx/types.js)。

¥Module (MDXModule from mdx/types.js).

nodeTypes

mdast-util-mdx 创建的节点类型列表,必须从 mdast 树到 hash 树(Array<string>)不受影响地传递。

¥List of node types made by mdast-util-mdx, which have to be passed through untouched from the mdast tree to the hast tree (Array<string>).

run(code, options)

运行使用 outputFormat: 'function-body' 编译的代码。

¥Run code compiled with outputFormat: 'function-body'.

☢️ 危险:这个 eval JavaScript。

¥☢️ Danger: this evals JavaScript.

参数

¥Parameters

  • code (VFilestring) — 要运行的 JavaScript 函数体

    ¥code (VFile or string) — JavaScript function body to run

  • optionsRunOptions,必填) - 配置

    ¥options (RunOptions, required) — configuration

返回

¥Returns

对模块的 Promise(Promise<MDXModule>mdx/types.js);结果是一个对象,其中 default 字段设置为组件;导出的任何其他内容也可用。

¥Promise to a module (Promise<MDXModule> from mdx/types.js); the result is an object with a default field set to the component; anything else that was exported is available too.

示例

¥Example

在服务器上:

¥On the server:

TypeScript
import {compile} from '@mdx-js/mdx'

const code = String(await compile('# hi', {outputFormat: 'function-body'}))
// To do: send `code` to the client somehow.

在客户端:

¥On the client:

TypeScript
import {run} from '@mdx-js/mdx'
import * as runtime from 'react/jsx-runtime'

const code = '' // To do: get `code` from server somehow.

const {default: Content} = await run(code, {...runtime, baseUrl: import.meta.url})

console.log(Content)

…产量:

¥…yields:

TypeScript
[Function: MDXContent]

runSync(code, options)

同步运行代码。

¥Run code, synchronously.

如果可能,请使用异步 run

¥When possible please use the async run.

☢️ 危险:这个 eval JavaScript。

¥☢️ Danger: this evals JavaScript.

参数

¥Parameters

  • code (VFilestring) — 要运行的 JavaScript 函数体

    ¥code (VFile or string) — JavaScript function body to run

  • optionsRunOptions,必填) - 配置

    ¥options (RunOptions, required) — configuration

返回

¥Returns

模块(MDXModulemdx/types.js)。

¥Module (MDXModule from mdx/types.js).

CompileOptions

compile(TypeScript 类型)的配置。

¥Configuration for compile (TypeScript type).

CompileOptionsProcessorOptions 相同,但 format 选项支持 'detect' 值(默认值)。'detect' 格式意味着对扩展名为 mdExtensions 的文件使用 'md',否则使用 'mdx'

¥CompileOptions is the same as ProcessorOptions with the exception that the format option supports a 'detect' value, which is the default. The 'detect' format means to use 'md' for files with an extension in mdExtensions and 'mdx' otherwise.

类型

¥Type

TypeScript
/**

 * Configuration for `compile`
 */
type CompileOptions = Omit<ProcessorOptions, 'format'> & {
  /**

   * Format of `file` (default: `'detect'`).
   */
  format?: 'detect' | 'md' | 'mdx' | null | undefined
}

EvaluateOptions

evaluate(TypeScript 类型)的配置。

¥Configuration for evaluate (TypeScript type).

EvaluateOptionsCompileOptions 相同,只是不允许使用选项 baseUrljsxjsxImportSourcejsxRuntimeoutputFormatpragmapragmaFragpragmaImportSourceproviderImportSource,并且还使用 RunOptions

¥EvaluateOptions is the same as CompileOptions, except that the options baseUrl, jsx, jsxImportSource, jsxRuntime, outputFormat, pragma, pragmaFrag, pragmaImportSource, and providerImportSource are not allowed, and that RunOptions are also used.

类型

¥Type

TypeScript
/**

 * Configuration for `evaluate`.
 */
type EvaluateOptions = Omit<
  CompileOptions,
  | 'baseUrl' // Note that this is also in `RunOptions`.
  | 'jsx'
  | 'jsxImportSource'
  | 'jsxRuntime'
  | 'outputFormat'
  | 'pragma'
  | 'pragmaFrag'
  | 'pragmaImportSource'
  | 'providerImportSource'
> &
  RunOptions

Fragment

代表子项,通常是一个符号(TypeScript 类型)。

¥Represent the children, typically a symbol (TypeScript type).

类型

¥Type

TypeScript
type Fragment = unknown

Jsx

创建一个生产元素(TypeScript 类型)。

¥Create a production element (TypeScript type).

参数

¥Parameters

  • type (unknown) — 元素类型:Fragment 符号、标签名称 (string)、组件

    ¥type (unknown) — element type: Fragment symbol, tag name (string), component

  • properties (Properties) — 元素属性和 children

    ¥properties (Properties) — element properties and children

  • keystringundefined)— 使用键

    ¥key (string or undefined) — key to use

返回

¥Returns

框架中的元素 (JSX.Element)。

¥Element from your framework (JSX.Element).

JsxDev

创建一个开发元素(TypeScript 类型)。

¥Create a development element (TypeScript type).

参数

¥Parameters

  • type (unknown) — 元素类型:Fragment 符号、标签名称 (string)、组件

    ¥type (unknown) — element type: Fragment symbol, tag name (string), component

  • properties (Properties) — 元素属性和 children

    ¥properties (Properties) — element properties and children

  • keystringundefined)— 使用键

    ¥key (string or undefined) — key to use

  • isStaticChildren (boolean) — 是否传递两个或多个子级(在数组中),即是否使用 jsxsjsx

    ¥isStaticChildren (boolean) — whether two or more children are passed (in an array), which is whether jsxs or jsx would be used

  • source (Source) — 有关来源的信息

    ¥source (Source) — info about source

  • self (unknown) — 上下文对象 (this)

    ¥self (unknown) — context object (this)

ProcessorOptions

createProcessor(TypeScript 类型)的配置。

¥Configuration for createProcessor (TypeScript type).

字段

¥Fields

  • SourceMapGenerator (SourceMapGenerator from source-map, 可选) — 添加源映射(对象形式)作为结果文件上的 map 字段

    ¥SourceMapGenerator (SourceMapGenerator from source-map, optional) — add a source map (object form) as the map field on the resulting file

Expand example

Assuming example.mdx from § Use exists, then:

TypeScript
import fs from 'node:fs/promises'
import {compile} from '@mdx-js/mdx'
import {SourceMapGenerator} from 'source-map'

const file = await compile(
  {path: 'example.mdx', value: await fs.readFile('example.mdx')},
  {SourceMapGenerator}
)

console.log(file.map)

…yields:

TypeScript
{
  file: 'example.mdx',
  mappings: ';;aAAaA,QAAQ;YAAQ;;;;;;;;iBAE3B',
  names: ['Thing'],
  sources: ['example.mdx'],
  version: 3
}
  • baseUrlURLstring,可选,示例:import.meta.url)— 将此 URL 用作 import.meta.url 并解析相对于它的 importexport … from

    ¥baseUrl (URL or string, optional, example: import.meta.url) — use this URL as import.meta.url and resolve import and export … from relative to it

Expand example

Say we have a module example.js:

TypeScript
import {compile} from '@mdx-js/mdx'

const code = 'export {number} from "./data.js"\n\n# hi'
const baseUrl = 'https://a.full/url' // Typically `import.meta.url`

console.log(String(await compile(code, {baseUrl})))

…now running node example.js yields:

TypeScript
import {jsx as _jsx} from 'react/jsx-runtime'
export {number} from 'https://a.full/data.js'
function _createMdxContent(props) { /* … */ }
export default function MDXContent(props = {}) { /* … */ }
  • development (boolean,默认值:false) — 是否在生成的代码中向错误消息添加额外信息并使用开发自动 JSX 运行时(/jsx-dev-runtime 中的 FragmentjsxDEV);当通过 Vite 使用 webpack 加载器 (@mdx-js/loader) 或 Rollup 集成 (@mdx-js/rollup) 时,这是根据你如何配置这些工具自动推断出来的

    ¥development (boolean, default: false) — whether to add extra info to error messages in generated code and use the development automatic JSX runtime (Fragment and jsxDEV from /jsx-dev-runtime); when using the webpack loader (@mdx-js/loader) or the Rollup integration (@mdx-js/rollup) through Vite, this is automatically inferred from how you configure those tools

Expand example

Say we had some MDX that references a component that can be passed or provided at runtime:

MDX
**Note**<NoteIcon />: some stuff.

And a module to evaluate that:

TypeScript
import fs from 'node:fs/promises'
import {evaluate} from '@mdx-js/mdx'
import * as runtime from 'react/jsx-runtime'

const path = 'example.mdx'
const value = await fs.readFile(path)
const MDXContent = (await evaluate({path, value}, {...runtime, baseUrl: import.meta.url})).default

console.log(MDXContent({}))

…running that would normally (production) yield:

Plain text
Error: Expected component `NoteIcon` to be defined: you likely forgot to import, pass, or provide it.
    at _missingMdxReference (eval at run (…/@mdx-js/mdx/lib/run.js:18:10), <anonymous>:27:9)
    at _createMdxContent (eval at run (…/@mdx-js/mdx/lib/run.js:18:10), <anonymous>:15:20)
    at MDXContent (eval at run (…/@mdx-js/mdx/lib/run.js:18:10), <anonymous>:9:9)
    at main (…/example.js:11:15)

…but if we add development: true to our example:

Diff
@@ -7,6 +7,6 @@
import fs from 'node:fs/promises'
-import * as runtime from 'react/jsx-runtime'
+import * as runtime from 'react/jsx-dev-runtime'
import {evaluate} from '@mdx-js/mdx'

const path = 'example.mdx'
const value = await fs.readFile(path)
-const MDXContent = (await evaluate({path, value}, {...runtime, baseUrl: import.meta.url})).default
+const MDXContent = (await evaluate({path, value}, {development: true, ...runtime, baseUrl: import.meta.url})).default

console.log(MDXContent({}))

…and we’d run it again, we’d get:

Plain text
Error: Expected component `NoteIcon` to be defined: you likely forgot to import, pass, or provide it.
It’s referenced in your code at `1:9-1:21` in `example.mdx`
provide it.
    at _missingMdxReference (eval at run (…/@mdx-js/mdx/lib/run.js:18:10), <anonymous>:27:9)
    at _createMdxContent (eval at run (…/@mdx-js/mdx/lib/run.js:18:10), <anonymous>:15:20)
    at MDXContent (eval at run (…/@mdx-js/mdx/lib/run.js:18:10), <anonymous>:9:9)
    at main (…/example.js:11:15)
  • elementAttributeNameCase'html''react,默认值:'react')— 用于属性名称的大小写;HTML 大小写例如为 classstroke-linecapxml:lang;React 外壳例如为 classNamestrokeLinecapxmlLang;对于用 MDX 编写的 JSX 组件,作者必须了解它们使用哪个框架并相应地编写代码;对于该项目生成的 AST 节点,此选项对其进行配置

    ¥elementAttributeNameCase ('html' or 'react, default: 'react') — casing to use for attribute names; HTML casing is for example class, stroke-linecap, xml:lang; React casing is for example className, strokeLinecap, xmlLang; for JSX components written in MDX, the author has to be aware of which framework they use and write code accordingly; for AST nodes generated by this project, this option configures it

  • format'md''mdx',默认:'mdx') - 文件的格式;'md' 表示视为 markdown,'mdx' 表示视为 MDX

    ¥format ('md' or 'mdx', default: 'mdx') — format of the file; 'md' means treat as markdown and 'mdx' means treat as MDX

Expand example
TypeScript
compile('') // Seen as MDX.
compile('', {format: 'mdx'}) // Seen as MDX.
compile('', {format: 'md'}) // Seen as markdown.
  • jsxboolean,默认:false) - 是否保留 JSX;默认情况下编译 JSX,以便生成的文件可以立即运行。

    ¥jsx (boolean, default: false) — whether to keep JSX; the default is to compile JSX away so that the resulting file is immediately runnable.

Expand example

If file is the contents of example.mdx from § Use, then:

TypeScript
compile(file, {jsx: true})

…yields this difference:

Diff
-import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
+/*@jsxRuntime automatic*/
+/*@jsxImportSource react*/

export function Thing() {
-  return _jsx(_Fragment, {children: 'World'})
+  return <>World!</>
}

function _createMdxContent(props) {
  const _components = {
    h1: 'h1',
    ...props.components
  }
-  return _jsxs(_components.h1, {children: ['Hello ', _jsx(Thing, {})]})
+  return <_components.h1>{"Hello "}<Thing /></_components.h1>
}

export default function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || {}
  return MDXLayout
-    ? _jsx(MDXLayout, {
-        ...props,
-        children: _jsx(_createMdxContent, props)
-      })
+    ? <MDXLayout {...props}><_createMdxContent {...props} /></MDXLayout>
    : _createMdxContent(props)
}
}
  • jsxImportSource (string,默认值:'react') — 导入自动 JSX 运行时的位置;当在 automatic 运行时时,这用于定义 FragmentjsxjsxDEVjsxs 的导入

    ¥jsxImportSource (string, default: 'react') — place to import automatic JSX runtimes from; when in the automatic runtime, this is used to define an import for Fragment, jsx, jsxDEV, and jsxs

Expand example

If file is the contents of example.mdx from § Use, then:

TypeScript
compile(file, {jsxImportSource: 'preact'})

…yields this difference:

Diff
-import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
+import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from 'preact/jsx-runtime'
  • jsxRuntime'automatic''classic',默认值:'automatic') - 要使用的 JSX 运行时;自动运行时编译为 import _jsx from '$importSource/jsx-runtime'\n_jsx('p');经典运行时编译为诸如 h('p') 之类的调用

    ¥jsxRuntime ('automatic' or 'classic', default: 'automatic') — JSX runtime to use; the automatic runtime compiles to import _jsx from '$importSource/jsx-runtime'\n_jsx('p'); the classic runtime compiles to calls such as h('p')

    👉 注意:对经典运行时的支持已被弃用,并且可能会在下一个主要版本中删除。

    ¥👉 Note: support for the classic runtime is deprecated and will likely be removed in the next major version.

Expand example

If file is the contents of example.mdx from § Use, then:

TypeScript
compile(file, {jsxRuntime: 'classic'})

…yields this difference:

Diff
-import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
+import React from 'react'

export function Thing() {
-  return _jsx(_Fragment, {children: 'World'})
+  return React.createElement(React.Fragment, null, 'World!')
}
…
  • outputFormat'function-body''program',默认:'program')— 要生成的输出格式;在大多数情况下应该使用 'program',它会生成一个完整的程序;evaluate 内部使用 'function-body' 编译为可以传递给 run 的代码;在某些情况下,你可能希望 evaluate 在单独的步骤中执行操作,例如在服务器上编译并在客户端上运行时。

    ¥outputFormat ('function-body' or 'program', default: 'program') — output format to generate; in most cases 'program' should be used, it results in a whole program; internally evaluate uses 'function-body' to compile to code that can be passed to run; in some cases, you might want what evaluate does in separate steps, such as when compiling on the server and running on the client.

Expand example

With a module example.js:

TypeScript
import {compile} from '@mdx-js/mdx'

const code = 'export const no = 3.14\n\n# hi {no}'

console.log(String(await compile(code, {outputFormat: 'program'}))) // Default.
console.log(String(await compile(code, {outputFormat: 'function-body'})))

…yields:

TypeScript
import {jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
export const no = 3.14
function _createMdxContent(props) { /* … */ }
export default function MDXContent(props = {}) { /* … */ }
TypeScript
'use strict'
const {Fragment: _Fragment, jsx: _jsx} = arguments[0]
const no = 3.14
function _createMdxContent(props) { /* … */ }
function MDXContent(props = {}) { /* … */ }
return {no, default: MDXContent}

The 'program' format will use import statements to import the runtime (and optionally provider) and use an export statement to yield the MDXContent component.

The 'function-body' format will get the runtime (and optionally provider) from arguments[0], rewrite export statements, and use a return statement to yield what was exported.

  • mdExtensions (Array<string>, 默认值: ['.md', '.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mkdown', '.ron']) — Markdown 扩展列表,带点影响 § 集成

    ¥mdExtensions (Array<string>, default: ['.md', '.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mkdown', '.ron']) — list of markdown extensions, with dot affects § Integrations

  • mdxExtensions (Array<string>,默认值:['.mdx']) — MDX 扩展列表,带点;影响 § 集成

    ¥mdxExtensions (Array<string>, default: ['.mdx']) — list of MDX extensions, with dot; affects § Integrations

  • pragma (string,默认值:'React.createElement') — JSX 的编译指示,在经典运行时中用作函数调用的标识符:<x />React.createElement('x');更改此设置时,你还应该定义 pragmaFragpragmaImportSource

    ¥pragma (string, default: 'React.createElement') — pragma for JSX, used in the classic runtime as an identifier for function calls: <x /> to React.createElement('x'); when changing this, you should also define pragmaFrag and pragmaImportSource too

    👉 注意:对经典运行时的支持已被弃用,并且可能会在下一个主要版本中删除。

    ¥👉 Note: support for the classic runtime is deprecated and will likely be removed in the next major version.

Expand example

If file is the contents of example.mdx from § Use, then:

TypeScript
compile(file, {
  jsxRuntime: 'classic',
  pragma: 'preact.createElement',
  pragmaFrag: 'preact.Fragment',
  pragmaImportSource: 'preact/compat'
})

…yields this difference:

Diff
-import React from 'react'
+import preact from 'preact/compat'

export function Thing() {
-  return React.createElement(React.Fragment, null, 'World!')
+  return preact.createElement(preact.Fragment, null, 'World!')
}
…
  • pragmaFrag (string, 默认值: 'React.Fragment') — 片段符号的编译指示,在经典运行时中用作未命名调用的标识符:<>React.createElement(React.Fragment);更改此设置时,你还应该定义 pragmapragmaImportSource

    ¥pragmaFrag (string, default: 'React.Fragment') — pragma for fragment symbol, used in the classic runtime as an identifier for unnamed calls: <> to React.createElement(React.Fragment); when changing this, you should also define pragma and pragmaImportSource too

    👉 注意:对经典运行时的支持已被弃用,并且可能会在下一个主要版本中删除。

    ¥👉 Note: support for the classic runtime is deprecated and will likely be removed in the next major version.

  • pragmaImportSource (string, 默认: 'react') — 从哪里导入 pragma 的标识符,在经典运行时使用;举例来说,当 pragma'a.b'pragmaImportSource'c' 时,将生成以下结果:import a from 'c'a.b('h1', {}) 之类的东西;更改此设置时,你还应该定义 pragmapragmaFrag

    ¥pragmaImportSource (string, default: 'react') — where to import the identifier of pragma from, used in the classic runtime; to illustrate, when pragma is 'a.b' and pragmaImportSource is 'c' the following will be generated: import a from 'c' and things such as a.b('h1', {}); when changing this, you should also define pragma and pragmaFrag too

    👉 注意:对经典运行时的支持已被弃用,并且可能会在下一个主要版本中删除。

    ¥👉 Note: support for the classic runtime is deprecated and will likely be removed in the next major version.

  • providerImportSource (string,可选,示例:'@mdx-js/react') — 导入提供者的位置;通常它用于支持上下文(React、Preact)的运行时,但它可以用于将组件注入到编译后的代码中;该模块必须导出标识符 useMDXComponents,在不带参数的情况下调用该标识符以获取组件对象(请参阅 UseMdxComponents

    ¥providerImportSource (string, optional, example: '@mdx-js/react') — place to import a provider from; normally it’s used for runtimes that support context (React, Preact), but it can be used to inject components into the compiled code; the module must export and identifier useMDXComponents which is called without arguments to get an object of components (see UseMdxComponents)

Expand example

If file is the contents of example.mdx from § Use, then:

TypeScript
compile(file, {providerImportSource: '@mdx-js/react'})

…yields this difference:

Diff
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
+import {useMDXComponents as _provideComponents} from '@mdx-js/react'

export function Thing() {
  return _jsx(_Fragment, {children: 'World'})
}

function _createMdxContent(props) {
  const _components = {
    h1: 'h1',
+    ..._provideComponents(),
    ...props.components
  }
  return _jsxs(_components.h1, {children: ['Hello ', _jsx(Thing, {})]})
}

export default function MDXContent(props = {}) {
-  const {wrapper: MDXLayout} = props.components || {}
+  const {wrapper: MDXLayout} = {
+    ..._provideComponents(),
+    ...props.components
+  }

  return MDXLayout
    ? _jsx(MDXLayout, {...props, children: _jsx(_createMdxContent, {})})
    : _createMdxContent()
  • recmaPluginsPluggableListunified,可选) - recma 插件列表;这是一个新的生态系统,目前处于测试阶段,用于改造 esast 树 (JavaScript)

    ¥recmaPlugins (PluggableList from unified, optional) — list of recma plugins; this is a new ecosystem, currently in beta, to transform esast trees (JavaScript)

Expand example
TypeScript
import recmaMdxIsMdxComponent from 'recma-mdx-is-mdx-component'

await compile(file, {recmaPlugins: [recmaMdxIsMdxComponent]})
Expand example
TypeScript
import rehypeKatex from 'rehype-katex' // Render math with KaTeX.
import remarkMath from 'remark-math' // Support math like `$so$`.

await compile(file, {rehypePlugins: [rehypeKatex], remarkPlugins: [remarkMath]})

await compile(file, {
  // A plugin with options:
  rehypePlugins: [[rehypeKatex, {strict: true, throwOnError: true}]],
  remarkPlugins: [remarkMath]
})
Expand example
TypeScript
import remarkFrontmatter from 'remark-frontmatter' // YAML and such.
import remarkGfm from 'remark-gfm' // Tables, footnotes, strikethrough, task lists, literal URLs.

await compile(file, {remarkPlugins: [remarkGfm]}) // One plugin.
await compile(file, {remarkPlugins: [[remarkFrontmatter, 'toml']]}) // A plugin with options.
await compile(file, {remarkPlugins: [remarkGfm, remarkFrontmatter]}) // Two plugins.
await compile(file, {remarkPlugins: [[remarkGfm, {singleTilde: false}], remarkFrontmatter]}) // Two plugins, first w/ options.
  • remarkRehypeOptionsOptionsremark-rehype,可选)- 传递到 remark-rehype 的选项;选项 allowDangerousHtml 将始终设置为 true,并且 MDX 节点(请参阅 nodeTypes)将被传递;特别是,如果你的内容不是英文,你可能需要传递脚注的配置

    ¥remarkRehypeOptions (Options from remark-rehype, optional) — options to pass through to remark-rehype; the option allowDangerousHtml will always be set to true and the MDX nodes (see nodeTypes) are passed through; In particular, you might want to pass configuration for footnotes if your content is not in English

Expand example
TypeScript
compile({value: ''}, {remarkRehypeOptions: {clobberPrefix: 'comment-1'}})
  • stylePropertyNameCase'css''dom,默认值:'dom')— 用于 style 对象中属性名称的大小写;CSS 大小写例如为 background-color-webkit-line-clamp;DOM 大小写例如为 backgroundColorWebkitLineClamp;对于用 MDX 编写的 JSX 组件,作者必须了解它们使用哪个框架并相应地编写代码;对于该项目生成的 AST 节点,此选项对其进行配置

    ¥stylePropertyNameCase ('css' or 'dom, default: 'dom') — casing to use for property names in style objects; CSS casing is for example background-color and -webkit-line-clamp; DOM casing is for example backgroundColor and WebkitLineClamp; for JSX components written in MDX, the author has to be aware of which framework they use and write code accordingly; for AST nodes generated by this project, this option configures it

  • tableCellAlignToStyle (boolean, 默认: true) — 将 tdth 上过时的 align 属性转换为 CSS style 属性

    ¥tableCellAlignToStyle (boolean, default: true) — turn obsolete align properties on td and th into CSS style properties

RunOptions

用于运行编译代码(TypeScript 类型)的配置。

¥Configuration to run compiled code (TypeScript type).

Fragmentjsxjsxs 在生产模式 (development: false) 下编译代码时使用。FragmentjsxDEV 在开发模式(development: true)下编译时使用。当使用 providerImportSource: '#' 编译代码时使用 useMDXComponents(此编译选项的确切值并不重要)。

¥Fragment, jsx, and jsxs are used when the code is compiled in production mode (development: false). Fragment and jsxDEV are used when compiled in development mode (development: true). useMDXComponents is used when the code is compiled with providerImportSource: '#' (the exact value of this compile option doesn’t matter).

字段

¥Fields

  • FragmentFragment,必需)- 用于片段的符号

    ¥Fragment (Fragment, required) — symbol to use for fragments

  • baseUrlURLstring,可选,例如:import.meta.url)— 将此 URL 用作 import.meta.url,并解析与之相关的 importexport … from;该选项也可以在 CompileOptions 中编译时给出;你应该传递这个(可能在运行时),因为否则在使用 import.meta.url / import / export … from 时可能会出现运行时错误

    ¥baseUrl (URL or string, optional, example: import.meta.url) — use this URL as import.meta.url and resolve import and export … from relative to it; this option can also be given at compile time in CompileOptions; you should pass this (likely at runtime), as you might get runtime errors when using import.meta.url / import / export … from otherwise

  • jsx (Jsx, 可选) — 在生产模式下生成具有静态子元素的元素的函数

    ¥jsx (Jsx, optional) — function to generate an element with static children in production mode

  • jsxDEV (JsxDev, 可选) — 在开发模式下生成元素的函数

    ¥jsxDEV (JsxDev, optional) — function to generate an element in development mode

  • jsxsJsx,可选)- 在生产模式下生成具有动态子元素的元素的函数

    ¥jsxs (Jsx, optional) — function to generate an element with dynamic children in production mode

  • useMDXComponents (UseMdxComponents, 可选) — 获取要使用的组件的函数

    ¥useMDXComponents (UseMdxComponents, optional) — function to get components to use

示例

¥Examples

/jsx-runtime 模块将公开 Fragmentjsxjsxs

¥A /jsx-runtime module will expose Fragment, jsx, and jsxs:

TypeScript
import * as runtime from 'react/jsx-runtime'

const {default: Content} = await evaluate('# hi', {...runtime, baseUrl: import.meta.url, ...otherOptions})

/jsx-dev-runtime 模块将公开 FragmentjsxDEV

¥A /jsx-dev-runtime module will expose Fragment and jsxDEV:

TypeScript
import * as runtime from 'react/jsx-dev-runtime'

const {default: Content} = await evaluate('# hi', {development: true, baseUrl: import.meta.url, ...runtime, ...otherOptions})

我们的提供商将公开 useMDXComponents

¥Our providers will expose useMDXComponents:

TypeScript
import * as provider from '@mdx-js/react'
import * as runtime from 'react/jsx-runtime'

const {default: Content} = await evaluate('# hi', {...provider, ...runtime, baseUrl: import.meta.url, ...otherOptions})

UseMdxComponents

获取组件(TypeScript 类型)。

¥Get components (TypeScript type).

参数

¥Parameters

没有参数。

¥There are no parameters.

返回

¥Returns

组件 (MDXComponentsmdx/types.js)。

¥Components (MDXComponents from mdx/types.js).

类型

¥Types

该包完全采用 TypeScript 类型。它导出附加类型 CompileOptionsEvaluateOptionsFragmentJsxJsxDevProcessorOptionsRunOptionsUseMdxComponents

¥This package is fully typed with TypeScript. It exports the additional types CompileOptions, EvaluateOptions, Fragment, Jsx, JsxDev, ProcessorOptions, RunOptions, and UseMdxComponents.

为了使评估的 MDX 类型正常工作,请确保键入 TypeScript JSX 命名空间。这是通过安装和使用框架类型来完成的,例如 @types/react。请参阅我们网站上的 § 类型 了解信息。

¥For types of evaluated MDX to work, make sure the TypeScript JSX namespace is typed. This is done by installing and using the types of your framework, such as @types/react. See § Types on our website for information.

架构

¥Architecture

要了解这个项目的用途,首先了解 Unified 的用途非常重要:请通读 unifiedjs/unified 自述文件(需要阅读 API 部分之前的部分)。

¥To understand what this project does, it’s very important to first understand what unified does: please read through the unifiedjs/unified readme (the part until you hit the API section is required reading).

@mdx-js/mdx 是一个统一的管道 - 经过封装,因此大多数人不需要了解统一。处理器执行以下步骤:

¥@mdx-js/mdx is a unified pipeline — wrapped so that most folks don’t need to know about unified. The processor goes through these steps:

  1. 将 MDX(带有嵌入式 JSX、ESM 和表达式的序列化 Markdown)解析为 mdast(Markdown 语法树)

    ¥parse MDX (serialized markdown with embedded JSX, ESM, and expressions) to mdast (markdown syntax tree)

  2. 通过 remark 进行转换(Markdown 生态系统)

    ¥transform through remark (markdown ecosystem)

  3. 将 mdast 转换为 hast (HTML 语法树)

    ¥transform mdast to hast (HTML syntax tree)

  4. 通过 rehype 进行转换(HTML 生态系统)

    ¥transform through rehype (HTML ecosystem)

  5. 将 hast 转换为 esast(JS 语法树)

    ¥transform hast to esast (JS syntax tree)

  6. 完成获取组件所需的工作

    ¥do the work needed to get a component

  7. 通过 recma(JS 生态系统)进行转换

    ¥transform through recma (JS ecosystem)

  8. 将 esast 序列化为 JavaScript

    ¥serialize esast as JavaScript

输入是 MDX(带有嵌入式 JSX、ESM 和表达式的序列化 Markdown)。markdown 使用 micromark/micromark 和嵌入式 JS 及其扩展之一 micromark/micromark-extension-mdxjs 进行解析(后者又使用 acorn)。然后使用 syntax-tree/mdast-util-from-markdown 及其扩展 syntax-tree/mdast-util-mdx 将解析器的结果转换为语法树:mdast

¥The input is MDX (serialized markdown with embedded JSX, ESM, and expressions). The markdown is parsed with micromark/micromark and the embedded JS with one of its extensions micromark/micromark-extension-mdxjs (which in turn uses acorn). Then syntax-tree/mdast-util-from-markdown and its extension syntax-tree/mdast-util-mdx are used to turn the results from the parser into a syntax tree: mdast.

Markdown 最接近源格式。这就是 remark 插件 发挥作用的地方。通常情况下,这里不应该发生太多事情。但也许你想支持 GFM(表格等)或 frontmatter?然后你可以在这里添加一个插件:分别为 remark-gfmremark-frontmatter

¥Markdown is closest to the source format. This is where remark plugins come in. Typically, there shouldn’t be much going on here. But perhaps you want to support GFM (tables and such) or frontmatter? Then you can add a plugin here: remark-gfm or remark-frontmatter, respectively.

Markdown 之后,我们进入 hast(HTML)。这个转变是由 syntax-tree/mdast-util-to-hast 完成的。等等,为什么,HTML 需要什么?部分原因是我们关心 HTML 语义:我们想知道某个东西是 <a>,而不是它是与资源的链接 ([text](url)) 还是对已定义链接定义的引用 ([text][id]\n\n[id]: url)。所以 HTML AST 更接近我们想要的目标。另一个原因是,当人们使用 MDX -> JS、markdown -> HTML,甚至只处理 HTML -> HTML 时,需要很多东西:MDX 以外的用例。通过在这些情况下使用单个 AST 并编写一个适用于该 AST 的插件,该插件可以支持所有这些用例(例如,用于语法高亮的 rehypejs/rehype-highlight 或用于数学的 rehypejs/rehype-katex)。所以,这就是 rehype 插件 的用武之地:可能是大多数插件。

¥After markdown, we go to hast (HTML). This transformation is done by syntax-tree/mdast-util-to-hast. Wait, why, what is HTML needed? Part of the reason is that we care about HTML semantics: we want to know that something is an <a>, not whether it’s a link with a resource ([text](url)) or a reference to a defined link definition ([text][id]\n\n[id]: url). So an HTML AST is closer to where we want to go. Another reason is that there are many things folks need when they go MDX -> JS, markdown -> HTML, or even folks who only process their HTML -> HTML: use cases other than MDX. By having a single AST in these cases and writing a plugin that works on that AST, that plugin can supports all these use cases (for example, rehypejs/rehype-highlight for syntax highlighting or rehypejs/rehype-katex for math). So, this is where rehype plugins come in: most of the plugins, probably.

然后我们转到 JavaScript:esast(JS;与 estree 兼容的 AST,但看起来更像其他 unist AST)。这个转变是由 rehype-recma 完成的。这是一个新的生态系统,还没有实用程序或插件。但这正是 @mdx-js/mdx 发挥作用的地方:它在其中添加导入/导出,在其中将 JSX 编译为 _jsx() 调用,以及在其中执行它提供的其他很酷的事情。

¥Then we go to JavaScript: esast (JS; an AST which is compatible with estree but looks a bit more like other unist ASTs). This transformation is done by rehype-recma. This is a new ecosystem that does not have utilities or plugins yet. But it’s where @mdx-js/mdx does its thing: where it adds imports/exports, where it compiles JSX away into _jsx() calls, and where it does the other cool things that it provides.

最后,输出是序列化的 JavaScript。最后一步是由 astring 完成的,它是一个小型且快速的 JS 生成器。

¥Finally, The output is serialized JavaScript. That final step is done by astring, a small and fast JS generator.

兼容性

¥Compatibility

由统一集体维护的项目与 Node.js 的维护版本兼容。

¥Projects maintained by the unified collective are compatible with maintained versions of Node.js.

当我们削减新的主要版本时,我们会放弃对未维护的 Node.js 版本的支持。这意味着我们尝试保持当前版本 @mdx-js/mdx@^3 与 Node.js 16 兼容。

¥When we cut a new major release, we drop support for unmaintained versions of Node. This means we try to keep the current release line, @mdx-js/mdx@^3, compatible with Node.js 16.

安全

¥Security

请参阅我们网站上的 § 安全 了解信息。

¥See § Security on our website for information.

贡献

¥Contribute

请参阅我们网站上的 § 贡献 了解入门方法。请参阅 § 支持 了解获取帮助的方法。

¥See § Contribute on our website for ways to get started. See § Support for ways to get help.

该项目有 行为守则。通过与此存储库、组织或社区交互,你同意遵守其条款。

¥This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.

许可证

¥License

MIT © 合成器和 Vercel

¥MIT © Compositor and Vercel

MDX 中文网 - 粤ICP备13048890号