@mdx-js/mdx
MDX compiler.
Contents
compile(file, options?)
compileSync(file, options?)
createProcessor(options?)
evaluate(file, options)
evaluateSync(file, options)
nodeTypes
run(code, options)
runSync(code, options)
CompileOptions
EvaluateOptions
Fragment
Jsx
JsxDev
ProcessorOptions
RunOptions
UseMdxComponents
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 (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 § Integrationsintegrations.Install
This package is ESM onlyesm. In Node.js (version 16+), install with npm:npm install @mdx-js/mdx
In Deno with
esm.sh
esmsh:import {compile} from 'https://esm.sh/@mdx-js/mdx@3'
In browsers with
esm.sh
esmsh:<script type="module">
import {compile} from 'https://esm.sh/@mdx-js/mdx@3?bundle'
</script>
Use
Say we have an MDX document,example.mdx
:export function Thing() {
return <>World!</>
}
# Hello, <Thing />
…and some code in
example.js
to compile example.mdx
to JavaScript: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:
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)
}
See § Using MDXusing-mdx for more on how MDX work and how to use the result.
API
This package exports the following identifiers:compile
api-compile,
compileSync
api-compile-sync,
createProcessor
api-create-processor,
evaluate
api-evaluate,
evaluateSync
api-evaluate-sync,
nodeTypes
api-node-types,
run
api-run, and
runSync
api-run-sync.
There is no default export.compile(file, options?)
Compile MDX to JS.Parameters
— MDX document to parseoptions
(CompileOptions
api-compile-options, optional)
Returns
Promise to compiled file (Promise<VFile>
vfile).Examples
The input value forfile
can be many different things.
You can pass a string
, Uint8Array
in UTF-8, VFile
vfile, or anything
that can be given to new VFile
.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: '🤭'}))
The output
VFile
can be used to access more than the generated code: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:
1:16-1:27 warning Emphasis should use `*` as a marker emphasis-marker remark-lint
⚠ 1 warning
compileSync(file, options?)
Synchronously compile MDX to JS.When possible please use the async
compile
api-compile.Parameters
— MDX document to parseoptions
(CompileOptions
api-compile-options, optional)
Returns
Compiled file (VFile
vfile).createProcessor(options?)
Create a processor to compile markdown or MDX to JavaScript.Note:format: 'detect'
is not allowed inProcessorOptions
.
Parameters
options
(ProcessorOptions
api-processor-options, optional)
Returns
Processor (Processor
from unified
unified-processor).evaluate(file, options)
Compileapi-compile and runapi-run MDX.When you trust your content,
evaluate
can work.
When possible, use compile
api-compile, write to a file, and then run with
Node or use one of the § Integrationsintegrations.☢️ Danger: it’s called evaluate because it eval
s JavaScript.
Parameters
— MDX document to parseoptions
(EvaluateOptions
api-evaluate-options, required)
Returns
Promise to a module (Promise<MDXModule>
from
mdx/types.js
mdx-types-module).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 § Useuse was in
file
, then:import {evaluate} from '@mdx-js/mdx'
import * as runtime from 'react/jsx-runtime'
console.log(await evaluate(file, runtime))
…yields:
{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 time, which cannot
be diffed:const {default: MDXContent} = await evaluate('…')
-<MDXContent {...props} />
+MDXContent(props)
evaluateSync(file, options)
Compile and run MDX, synchronously.When possible please use the async
evaluate
api-evaluate.☢️ Danger: it’s called evaluate because it eval
s JavaScript.
Parameters
— MDX document to parseoptions
(EvaluateOptions
api-evaluate-options, required)
Returns
Module (MDXModule
from mdx/types.js
mdx-types-module).nodeTypes
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)
Run code compiled with outputFormat: 'function-body'
.☢️ Danger: this eval
s JavaScript.
Parameters
— JavaScript function body to runoptions
(RunOptions
api-run-options, required)
Returns
Promise to a module (Promise<MDXModule>
from
mdx/types.js
mdx-types-module);
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: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:
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:
[Function: MDXContent]
runSync(code, options)
Run code, synchronously.When possible please use the async
run
api-run.☢️ Danger: this eval
s JavaScript.
Parameters
— JavaScript function body to runoptions
(RunOptions
api-run-options, required)
Returns
Module (MDXModule
from mdx/types.js
mdx-types-module).CompileOptions
Configuration for compile
(TypeScript type).CompileOptions
is the same as ProcessorOptions
api-processor-options
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
/**
* 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 CompileOptions
api-compile-options,
except that the options baseUrl
, jsx
, jsxImportSource
, jsxRuntime
,
outputFormat
, pragma
, pragmaFrag
, pragmaImportSource
, and
providerImportSource
are not allowed, and that
RunOptions
api-run-options are also used.Type
/**
* 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
Represent the children, typically a symbol (TypeScript type).Type
type Fragment = unknown
Jsx
Create a production element (TypeScript type).Parameters
type
(unknown
)
Fragment
symbol, tag name (string
), componentproperties
(Properties
)
children
key
(string
orundefined
)
Returns
Element from your framework (JSX.Element
).JsxDev
Create a development element (TypeScript type).Parameters
type
(unknown
)
Fragment
symbol, tag name (string
), componentproperties
(Properties
)
children
key
(string
orundefined
)
isStaticChildren
(boolean
)
jsxs
or jsx
would be usedsource
(Source
)
self
(unknown
)
this
)ProcessorOptions
Configuration for createProcessor
(TypeScript type).Fields
SourceMapGenerator
(SourceMapGenerator
fromsource-map
source-map,
map
field on the resulting fileExpand example
Assuming
example.mdx
from § Useuse exists, then:```tsx 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:
```tsx {
file: 'example.mdx',
mappings: ';;aAAaA,QAAQ;YAAQ;;;;;;;;iBAE3B',
names: ['Thing'],
sources: ['example.mdx'],
version: 3
}
```baseUrl
(URL
orstring
, optional, example:import.meta.url
)
import.meta.url
and resolve import
and
export … from
relative to itExpand example
Say we have a module
example.js
:```tsx 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:```tsx 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
, default:false
)
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 toolsExpand example
Say we had some MDX that references a component that can be passed or provided at runtime:
```mdx Note: some stuff. ```
And a module to evaluate that:
```tsx 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:
```txt 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:
```txt 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'
or'react
, default:'react'
)
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 itformat
('md'
or'mdx'
, default:'mdx'
)
'md'
means treat as markdown and 'mdx'
means treat as MDXmdx-syntaxExpand example
```tsx compile('…') // Seen as MDX. compile('…', {format: 'mdx'}) // Seen as MDX. compile('…', {format: 'md'}) // Seen as markdown. ```
jsx
(boolean
, default:false
)
Expand example
If
file
is the contents of example.mdx
from § Useuse, then:```tsx 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 "}components.h1>
}export default function MDXContent(props = {}) {
const {wrapper: MDXLayout} = props.components || {}
return MDXLayout
- ? jsx(MDXLayout, {
- ...props,
- children: jsx(createMdxContent, props)
- })
+ ? <createMdxContent {...props} />: _createMdxContent(props)
}
}
```jsxImportSource
(string
, default:'react'
)
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 § Useuse, then:```tsx 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'
or'classic'
, default:'automatic'
)
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 § Useuse, then:```tsx 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'
or'program'
, default:'program'
)
'program'
should be used, it results in a whole program;
internally evaluate
api-evaluate uses 'function-body'
to compile to
code that can be passed to run
api-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
:```tsx 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:
```tsx import {jsx as jsx, jsxs as jsxs} from 'react/jsx-runtime' export const no = 3.14 function createMdxContent(props) { / … / } export default function MDXContent(props = {}) { / … / } ```
```tsx 'use strict' const {Fragment: Fragment, jsx: jsx} = arguments0 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>
, default: `'.md', '.markdown', '.mdown',
mdxExtensions
(Array<string>
, default:['.mdx']
)
pragma
(string
, default:'React.createElement'
)
<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 § Useuse, then:```tsx 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
, default:'React.Fragment'
)
<>
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
, default:'react'
)
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
, optional, example:'@mdx-js/react'
)
useMDXComponents
which is called
without arguments to get an object of components (see
UseMdxComponents
api-use-mdx-components)Expand example
If
file
is the contents of example.mdx
from § Useuse, then:```tsx 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()
```recmaPlugins
(PluggableList
fromunified
unified-pluggable-list,
Expand example
```tsx import recmaMdxIsMdxComponent from 'recma-mdx-is-mdx-component'
await compile(file, {recmaPlugins: recmaMdxIsMdxComponent}) ```
rehypePlugins
(PluggableList
fromunified
unified-pluggable-list,
Expand example
```tsx 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]
})
```remarkPlugins
(PluggableList
fromunified
unified-pluggable-list,
Expand example
```tsx 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. ```
remarkRehypeOptions
(Options
from
remark-rehype
remark-rehype-options, optional)
— options to pass through to remark-rehype
;
the option allowDangerousHtml
will always be set to true
and the MDX
nodes (see nodeTypes
api-node-types) are passed through;
In particular, you might want to pass configuration for footnotes if your
content is not in EnglishExpand example
```tsx compile({value: '…'}, {remarkRehypeOptions: {clobberPrefix: 'comment-1'}}) ```
stylePropertyNameCase
('css'
or'dom
, default:'dom'
)
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 ittableCellAlignToStyle
(boolean
, default:true
)
align
properties on td
and th
into CSS style
propertiesRunOptions
Configuration to run compiled code (TypeScript type).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
Fragment
(Fragment
api-fragment, required)
baseUrl
(URL
orstring
, optional, example:import.meta.url
)
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
— function to generate an element with static children in production modejsxDEV
(JsxDev
api-jsx-dev, optional)
useMDXComponents
(UseMdxComponents
api-use-mdx-components, optional)
Examples
A/jsx-runtime
module will expose Fragment
, jsx
, and jsxs
:import * as runtime from 'react/jsx-runtime'
const {default: Content} = await evaluate('# hi', {...runtime, baseUrl: import.meta.url, ...otherOptions})
A
/jsx-dev-runtime
module will expose Fragment
and jsxDEV
:import * as runtime from 'react/jsx-dev-runtime'
const {default: Content} = await evaluate('# hi', {development: true, baseUrl: import.meta.url, ...runtime, ...otherOptions})
Our providers will expose
useMDXComponents
: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
Get components (TypeScript type).Parameters
There are no parameters.Returns
Components (MDXComponents
from mdx/types.js
mdx-types-components).Types
This package is fully typed with TypeScript. It exports the additional typesCompileOptions
api-compile-options,
EvaluateOptions
api-evaluate-options,
Fragment
api-fragment,
Jsx
api-jsx,
JsxDev
api-jsx-dev,
ProcessorOptions
api-processor-options,
RunOptions
api-run-options, and
UseMdxComponents
api-use-mdx-components.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 § Typestypes on our website for information.Architecture
To understand what this project does, it’s very important to first understand what unified does: please read through theunifiedjs/unified
unified readme
(the part until you hit the API section is required reading).@mdx-js/mdx
is a unified pipeline — wrapped so that most folks don’t need to
know about unified: core.js#L65
core.
The processor goes through these steps:- parse MDX (serialized markdown with embedded JSX, ESM, and expressions)
to mdast (markdown syntax tree)
- transform through remark (markdown ecosystem)
- transform mdast to hast (HTML syntax tree)
- transform through rehype (HTML ecosystem)
- transform hast to esast (JS syntax tree)
- do the work needed to get a component
- transform through recma (JS ecosystem)
- serialize esast as JavaScript
The input is MDX (serialized markdown with embedded JSX, ESM, and expressions). The markdown is parsed with
micromark/micromark
micromark and the embedded
JS with one of its extensions
micromark/micromark-extension-mdxjs
micromark-extension-mdxjs (which in
turn uses acorn).
Then syntax-tree/mdast-util-from-markdown
mdast-util-from-markdown and its
extension syntax-tree/mdast-util-mdx
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 pluginsremark-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.After markdown, we go to hast (HTML). This transformation is done by
syntax-tree/mdast-util-to-hast
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
rehype-highlight for syntax highlighting or
rehypejs/rehype-katex
rehype-katex for math).
So, this is where rehype pluginsrehype-plugins come in: most of the plugins,
probably.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
syntax-tree/hast-util-to-estree
hast-util-to-estree.
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.Finally, The output is serialized JavaScript. That final step is done by astring, a small and fast JS generator.
Compatibility
Projects maintained by the unified collective are compatible with maintained versions of Node.js.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 § Securitysecurity on our website for information.Contribute
See § Contributecontribute on our website for ways to get started. See § Supportsupport for ways to get help.This project has a code of conductcoc. By interacting with this repository, organization, or community you agree to abide by its terms.