×

注意!页面内容来自https://www.mdxjs.cn/packages/mdx/,本站不储存任何内容,为了更好的阅读体验进行在线解析,若有广告出现,请及时反馈。若您觉得侵犯了您的利益,请通知我们进行删除,然后访问 原网页

Skip to navigation
15-25 minutes read

@mdx-/mdx

MDX compiler.

Contents

What is this?

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

When should I use this?

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

Install

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

Shell
npm install @mdx-/mdx

In Deno with esm.sh:

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

In browsers with esm.sh:

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

Use

Say we have an MDX documentexample.mdx:

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

# Hello<Thing />

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

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

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

console.log(String(compiled))

Yields roughly:

TypeScript
import {Fragment as _Fragmentx as _xxs as _xs} from 'react/x-runtime'

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

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

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

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

API

This package exports the following identifiers: compilecompileSynccreateProcessorevaluateevaluateSyncnodeTypesrunand runSync. There is no default export.

compile(fileoptions?)

Compile MDX to JS.

Parameters
Returns

Promise to compiled file (Promise<VFile>).

Examples

The input value for file can be many different things. You can pass a stringUint8Array in UTF-8VFileor anything that can be given to new VFile.

TypeScript
import {compile} from '@mdx-/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: '🤭'}))

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

TypeScript
import {compile} from '@mdx-/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(fileoptions?)

Synchronously compile MDX to JS.

When possible please use the async compile.

Parameters
Returns

Compiled file (VFile).

createProcessor(options?)

Create a processor to compile markdown or MDX to JavaScript.

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

Parameters
Returns

Processor (Processor from unified).

evaluate(fileoptions)

Compile and run MDX.

When you trust your contentevaluate can work. When possibleuse compilewrite to a fileand then run with Node or use one of the § Integrations.

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

Parameters
Returns

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

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

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

console.log(await evaluate(fileruntime))

…yields:

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

Compiling (and running) MDX takes time.

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 timewhich cannot be diffed:

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

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

evaluateSync(fileoptions)

Compile and run MDXsynchronously.

When possible please use the async evaluate.

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

Parameters
Returns

Module (MDXModule from mdx/types.).

nodeTypes

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

run(codeoptions)

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

☢️ Danger: this evals JavaScript.

Parameters
  • code (VFile or string) — JavaScript function body to run
  • options (RunOptionsrequired) — configuration
Returns

Promise to a module (Promise<MDXModule> from mdx/types.); 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-/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-/mdx'
import * as runtime from 'react/x-runtime'

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

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

console.log(Content)

…yields:

TypeScript
[Function: MDXContent]

runSync(codeoptions)

Run codesynchronously.

When possible please use the async run.

☢️ Danger: this evals JavaScript.

Parameters
  • code (VFile or string) — JavaScript function body to run
  • options (RunOptionsrequired) — configuration
Returns

Module (MDXModule from mdx/types.).

CompileOptions

Configuration for compile (TypeScript type).

CompileOptions is the same as ProcessorOptions with the exception that the format option supports a 'detect' valuewhich 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

Configuration for evaluate (TypeScript type).

EvaluateOptions is the same as CompileOptionsexcept that the options baseUrlxxImportSourcexRuntimeoutputFormatpragmapragmaFragpragmaImportSourceand providerImportSource are not allowedand that RunOptions are also used.

Type
TypeScript
/**
 * Configuration for `evaluate`.
 */
type EvaluateOptions = Omit<
  CompileOptions,
  | 'baseUrl' // Note that this is also in `RunOptions`.
  | 'x'
  | 'xImportSource'
  | 'xRuntime'
  | 'outputFormat'
  | 'pragma'
  | 'pragmaFrag'
  | 'pragmaImportSource'
  | 'providerImportSource'
> &
  RunOptions

Fragment

Represent the childrentypically a symbol (TypeScript type).

Type
TypeScript
type Fragment = unknown

Jsx

Create a production element (TypeScript type).

Parameters
  • type (unknown) — element type: Fragment symboltag name (string)component
  • properties (Properties) — element properties and children
  • key (string or undefined) — key to use
Returns

Element from your framework (JSX.Element).

JsxDev

Create a development element (TypeScript type).

Parameters
  • type (unknown) — element type: Fragment symboltag name (string)component
  • properties (Properties) — element properties and children
  • key (string or undefined) — key to use
  • isStaticChildren (boolean) — whether two or more children are passed (in an array)which is whether xs or x would be used
  • source (Source) — info about source
  • self (unknown) — context object (this)

ProcessorOptions

Configuration for createProcessor (TypeScript type).

Fields
  • SourceMapGenerator (SourceMapGenerator from source-mapoptional) — add a source map (object form) as the map field on the resulting file

    Expand example

    Assuming example.mdx from § Use existsthen:

    TypeScript
    import fs from 'node:fs/promises'
    import {compile} from '@mdx-/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
    }
    
  • baseUrl (URL or stringoptionalexample: 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.:

    TypeScript
    import {compile} from '@mdx-/mdx'
    
    const code = 'export {number} from "./data."\n\n# hi'
    const baseUrl = 'https://a.full/url' // Typically `import.meta.url`
    
    console.log(String(await compile(code{baseUrl})))
    

    …now running node example. yields:

    TypeScript
    import {x as _x} from 'react/x-runtime'
    export {number} from 'https://a.full/data.'
    function _createMdxContent(props) { /* … */ }
    export default function MDXContent(props = {}) { /* … */ }
    
  • development (booleandefault: false) — whether to add extra info to error messages in generated code and use the development automatic JSX runtime (Fragment and xDEV from /x-dev-runtime); when using the webpack loader (@mdx-/loader) or the Rollup integration (@mdx-/rollup) through Vitethis 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-/mdx'
    import * as runtime from 'react/x-runtime'
    
    const path = 'example.mdx'
    const value = await fs.readFile(path)
    const MDXContent = (await evaluate({pathvalue}{...runtimebaseUrl: 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 importpassor provide it.
        at _missingMdxReference (eval at run (…/@mdx-/mdx/lib/run.:18:10)<anonymous>:27:9)
        at _createMdxContent (eval at run (…/@mdx-/mdx/lib/run.:18:10)<anonymous>:15:20)
        at MDXContent (eval at run (…/@mdx-/mdx/lib/run.:18:10)<anonymous>:9:9)
        at main (…/example.: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/x-runtime'
    +import * as runtime from 'react/x-dev-runtime'
    import {evaluate} from '@mdx-/mdx'
    
    const path = 'example.mdx'
    const value = await fs.readFile(path)
    -const MDXContent = (await evaluate({pathvalue}{...runtimebaseUrl: import.meta.url})).default
    +const MDXContent = (await evaluate({pathvalue}{development: true...runtimebaseUrl: import.meta.url})).default
    
    console.log(MDXContent({}))
    

    …and we’d run it againwe’d get:

    Plain text
    Error: Expected component `NoteIcon` to be defined: you likely forgot to importpassor provide it.
    It’s referenced in your code at `1:9-1:21` in `example.mdx`
    provide it.
        at _missingMdxReference (eval at run (…/@mdx-/mdx/lib/run.:18:10)<anonymous>:27:9)
        at _createMdxContent (eval at run (…/@mdx-/mdx/lib/run.:18:10)<anonymous>:15:20)
        at MDXContent (eval at run (…/@mdx-/mdx/lib/run.:18:10)<anonymous>:9:9)
        at main (…/example.:11:15)
    
  • elementAttributeNameCase ('html' or 'reactdefault: 'react') — casing to use for attribute names; HTML casing is for example classstroke-linecapxml:lang; React casing is for example classNamestrokeLinecapxmlLang; for JSX components written in MDXthe author has to be aware of which framework they use and write code accordingly; for AST nodes generated by this projectthis option configures it

  • 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.
    
  • x (booleandefault: 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 § Usethen:

    TypeScript
    compile(file{x: true})
    

    …yields this difference:

    Diff
    -import {Fragment as _Fragmentx as _xxs as _xs} from 'react/x-runtime'
    +/*@xRuntime automatic*/
    +/*@xImportSource react*/
    
    export function Thing() {
    -  return _x(_Fragment{children: 'World'})
    +  return <>World!</>
    }
    
    function _createMdxContent(props) {
      const _components = {
        h1: 'h1',
        ...props.components
      }
    -  return _xs(_components.h1{children: ['Hello '_x(Thing{})]})
    +  return <_components.h1>{"Hello "}<Thing /></_components.h1>
    }
    
    export default function MDXContent(props = {}) {
      const {wrapper: MDXLayout} = props.components || {}
      return MDXLayout
    -    ? _x(MDXLayout{
    -        ...props,
    -        children: _x(_createMdxContentprops)
    -      })
    +    ? <MDXLayout {...props}><_createMdxContent {...props} /></MDXLayout>
        : _createMdxContent(props)
    }
    }
    
  • xImportSource (stringdefault: 'react') — place to import automatic JSX runtimes from; when in the automatic runtimethis is used to define an import for FragmentxxDEVand xs

    Expand example

    If file is the contents of example.mdx from § Usethen:

    TypeScript
    compile(file{xImportSource: 'preact'})
    

    …yields this difference:

    Diff
    -import {Fragment as _Fragmentx as _xxs as _xs} from 'react/x-runtime'
    +import {Fragment as _Fragmentx as _xxs as _xs } from 'preact/x-runtime'
    
  • xRuntime ('automatic' or 'classic'default: 'automatic') — JSX runtime to use; the automatic runtime compiles to import _x from '$importSource/x-runtime'\n_x('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 § Usethen:

    TypeScript
    compile(file{xRuntime: 'classic'})
    

    …yields this difference:

    Diff
    -import {Fragment as _Fragmentx as _xxs as _xs} from 'react/x-runtime'
    +import React from 'react'
    
    export function Thing() {
    -  return _x(_Fragment{children: 'World'})
    +  return React.createElement(React.Fragmentnull'World!')
    }
    …
    
  • outputFormat ('function-body' or 'program'default: 'program') — output format to generate; in most cases 'program' should be usedit results in a whole program; internally evaluate uses 'function-body' to compile to code that can be passed to run; in some casesyou might want what evaluate does in separate stepssuch as when compiling on the server and running on the client.

    Expand example

    With a module example.:

    TypeScript
    import {compile} from '@mdx-/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 {x as _xxs as _xs} from 'react/x-runtime'
    export const no = 3.14
    function _createMdxContent(props) { /* … */ }
    export default function MDXContent(props = {}) { /* … */ }
    
    TypeScript
    'use strict'
    const {Fragment: _Fragmentx: _x} = arguments[0]
    const no = 3.14
    function _createMdxContent(props) { /* … */ }
    function MDXContent(props = {}) { /* … */ }
    return {nodefault: 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 statementsand use a return statement to yield what was exported.

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

  • mdxExtensions (Array<string>default: ['.mdx']) — list of MDX extensionswith dot; affects § Integrations

  • pragma (stringdefault: 'React.createElement') — pragma for JSXused in the classic runtime as an identifier for function calls: <x /> to React.createElement('x'); when changing thisyou 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 § Usethen:

    TypeScript
    compile(file{
      xRuntime: '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.Fragmentnull'World!')
    +  return preact.createElement(preact.Fragmentnull'World!')
    }
    …
    
  • pragmaFrag (stringdefault: 'React.Fragment') — pragma for fragment symbolused in the classic runtime as an identifier for unnamed calls: <> to React.createElement(React.Fragment); when changing thisyou 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 (stringdefault: 'react') — where to import the identifier of pragma fromused in the classic runtime; to illustratewhen 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 thisyou 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 (stringoptionalexample: '@mdx-/react') — place to import a provider from; normally it’s used for runtimes that support context (ReactPreact)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 § Usethen:

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

    …yields this difference:

    Diff
    import {Fragment as _Fragmentx as _xxs as _xs} from 'react/x-runtime'
    +import {useMDXComponents as _provideComponents} from '@mdx-/react'
    
    export function Thing() {
      return _x(_Fragment{children: 'World'})
    }
    
    function _createMdxContent(props) {
      const _components = {
        h1: 'h1',
    +    ..._provideComponents(),
        ...props.components
      }
      return _xs(_components.h1{children: ['Hello '_x(Thing{})]})
    }
    
    export default function MDXContent(props = {}) {
    -  const {wrapper: MDXLayout} = props.components || {}
    +  const {wrapper: MDXLayout} = {
    +    ..._provideComponents(),
    +    ...props.components
    +  }
    
      return MDXLayout
        ? _x(MDXLayout{...propschildren: _x(_createMdxContent{})})
        : _createMdxContent()
    
  • recmaPlugins (PluggableList from unifiedoptional) — list of recma plugins; this is a new ecosystemcurrently in betato transform esast trees (JavaScript)

    Expand example
    TypeScript
    import recmaMdxIsMdxComponent from 'recma-mdx-is-mdx-component'
    
    await compile(file{recmaPlugins: [recmaMdxIsMdxComponent]})
    
  • rehypePlugins (PluggableList from unifiedoptional) — list of rehype plugins

    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: truethrowOnError: true}]],
      remarkPlugins: [remarkMath]
    })
    
  • remarkPlugins (PluggableList from unifiedoptional) — list of remark plugins

    Expand example
    TypeScript
    import remarkFrontmatter from 'remark-frontmatter' // YAML and such.
    import remarkGfm from 'remark-gfm' // Tablesfootnotesstrikethroughtask listsliteral URLs.
    
    await compile(file{remarkPlugins: [remarkGfm]}) // One plugin.
    await compile(file{remarkPlugins: [[remarkFrontmatter'toml']]}) // A plugin with options.
    await compile(file{remarkPlugins: [remarkGfmremarkFrontmatter]}) // Two plugins.
    await compile(file{remarkPlugins: [[remarkGfm{singleTilde: false}]remarkFrontmatter]}) // Two pluginsfirst w/ options.
    
  • remarkRehypeOptions (Options from remark-rehypeoptional) — 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 particularyou might want to pass configuration for footnotes if your content is not in English

    Expand example
    TypeScript
    compile({value: ''}{remarkRehypeOptions: {clobberPrefix: 'comment-1'}})
    
  • PropertyNameCase ('css' or 'domdefault: 'dom') — casing to use for property names in 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 MDXthe author has to be aware of which framework they use and write code accordingly; for AST nodes generated by this projectthis option configures it

  • tableCellAlignToStyle (booleandefault: true) — turn obsolete align properties on td and th into CSS properties

RunOptions

Configuration to run compiled code (TypeScript type).

Fragmentxand xs are used when the code is compiled in production mode (development: false). Fragment and xDEV 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
  • Fragment (Fragmentrequired) — symbol to use for fragments
  • baseUrl (URL or stringoptionalexample: 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
  • x (Jsxoptional) — function to generate an element with static children in production mode
  • xDEV (JsxDevoptional) — function to generate an element in development mode
  • xs (Jsxoptional) — function to generate an element with dynamic children in production mode
  • useMDXComponents (UseMdxComponentsoptional) — function to get components to use
Examples

A /x-runtime module will expose Fragmentxand xs:

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

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

A /x-dev-runtime module will expose Fragment and xDEV:

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

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

Our providers will expose useMDXComponents:

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

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

UseMdxComponents

Get components (TypeScript type).

Parameters

There are no parameters.

Returns

Components (MDXComponents from mdx/types.).

Types

This package is fully typed with TypeScript. It exports the additional types CompileOptionsEvaluateOptionsFragmentJsxJsxDevProcessorOptionsRunOptionsand UseMdxComponents.

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

Architecture

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

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

  1. parse MDX (serialized markdown with embedded JSXESMand expressions) to mdast (markdown syntax tree)
  2. transform through remark (markdown ecosystem)
  3. transform mdast to hast (HTML syntax tree)
  4. transform through rehype (HTML ecosystem)
  5. transform hast to esast (JS syntax tree)
  6. do the work needed to get a component
  7. transform through recma (JS ecosystem)
  8. serialize esast as JavaScript

The input is MDX (serialized markdown with embedded JSXESMand expressions). The markdown is parsed with micromark/micromark and the embedded JS with one of its extensions micromark/micromark-extension-mdx (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 is closest to the source format. This is where remark plugins come in. Typicallythere 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-frontmatterrespectively.

After markdownwe go to hast (HTML). This transformation is done by syntax-tree/mdast-util-to-hast. Waitwhywhat 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 -> JSmarkdown -> HTMLor 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 ASTthat plugin can supports all these use cases (for examplerehype/rehype-highlight for syntax highlighting or rehype/rehype-katex for math). Sothis is where rehype plugins come in: most of the pluginsprobably.

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-/mdx does its thing: where it adds imports/exportswhere it compiles JSX away into _x() callsand where it does the other cool things that it provides.

FinallyThe output is serialized JavaScript. That final step is done by astringa small and fast JS generator.

Compatibility

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

When we cut a new major releasewe drop support for unmaintained versions of Node. This means we try to keep the current release line@mdx-/mdx@^3compatible with Node. 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 repositoryorganizationor community you agree to abide by its terms.

License

MIT © Compositor and Vercel