{"id":13472688,"url":"https://github.com/wooorm/xdm","last_synced_at":"2025-05-15T16:07:28.522Z","repository":{"id":43295703,"uuid":"337489224","full_name":"wooorm/xdm","owner":"wooorm","description":"Just a *really* good MDX compiler. No runtime. With esbuild, Rollup, and webpack plugins","archived":false,"fork":false,"pushed_at":"2022-03-09T11:27:47.000Z","size":1754,"stargazers_count":598,"open_issues_count":0,"forks_count":18,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-09T10:09:51.107Z","etag":null,"topics":["babel","esbuild","jsx","markdown","mdx","mdxjs","rollup","webpack"],"latest_commit_sha":null,"homepage":"http://wooorm.com/xdm/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wooorm.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":"funding.yml","license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"wooorm"}},"created_at":"2021-02-09T17:52:41.000Z","updated_at":"2025-05-02T12:01:57.000Z","dependencies_parsed_at":"2022-08-23T02:50:22.196Z","dependency_job_id":null,"html_url":"https://github.com/wooorm/xdm","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooorm%2Fxdm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooorm%2Fxdm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooorm%2Fxdm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wooorm%2Fxdm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wooorm","download_url":"https://codeload.github.com/wooorm/xdm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253481051,"owners_count":21915259,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["babel","esbuild","jsx","markdown","mdx","mdxjs","rollup","webpack"],"created_at":"2024-07-31T16:00:57.109Z","updated_at":"2025-05-15T16:07:28.496Z","avatar_url":"https://github.com/wooorm.png","language":"JavaScript","readme":"# xdm\n\n[![Build][build-badge]][build]\n[![Coverage][coverage-badge]][coverage]\n[![Downloads][downloads-badge]][downloads]\n[![Size][size-badge]][size]\n\nxdm was a fork (complete rewrite?) that envisioned how `mdx-js/mdx` could work.\nAll of xdm has now been ported into `mdx-js/mdx` making xdm no longer needed.\nUse [`mdx-js/mdx`][mdxjs] instead.\n\n\u003cdetails\u003e\u003csummary\u003eRead the original readme\u003c/summary\u003e\n\n**xdm** is an MDX compiler that focusses on two things:\n\n1.  Compiling the MDX syntax (markdown + JSX) to JavaScript\n2.  Making it easier to use the MDX syntax in different places\n\nThis is mostly things I wrote for `@mdx-js/mdx` which are not slated to be\nreleased (soon?) plus some further changes that I think are good ideas (source\nmaps, ESM only, defaulting to an automatic JSX runtime, no Babel, smallish\nbrowser size, more docs, import/exports in evaluate, esbuild and Rollup\nplugins).\n\nThere are also some cool experimental features in [👩‍🔬 Lab][lab]!\n\n## Install\n\nUse Node 12 or later.\nThen install `xdm` with either npm or yarn.\n\n[npm][]:\n\n```sh\nnpm install xdm\n```\n\n[yarn][]:\n\n```sh\nyarn add xdm\n```\n\nThis package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c):\nNode 12+ is needed to use it and it must be `import`ed instead of `require`d.\n\n## Contents\n\n*   [What is MDX?](#what-is-mdx)\n*   [Use](#use)\n*   [API](#api)\n    *   [`compile(file, options?)`](#compilefile-options)\n    *   [`compileSync(file, options?)`](#compilesyncfile-options)\n    *   [`evaluate(file, options)`](#evaluatefile-options)\n    *   [`evaluateSync(file, options)`](#evaluatesyncfile-options)\n    *   [`run(functionBody, options)`](#runfunctionbody-options)\n    *   [`runSync(functionBody, options)`](#runsyncfunctionbody-options)\n    *   [`createProcessor(options)`](#createprocessoroptions)\n*   [👩‍🔬 Lab](#-lab)\n    *   [Importing `.mdx` files directly](#importing-mdx-files-directly)\n    *   [Requiring `.mdx` files directly](#requiring-mdx-files-directly)\n    *   [Importing `.md` and `.mdx` files from the web in esbuild](#importing-md-and-mdx-files-from-the-web-in-esbuild)\n*   [MDX syntax](#mdx-syntax)\n    *   [Markdown](#markdown)\n    *   [JSX](#jsx)\n    *   [ESM](#esm)\n    *   [Expressions](#expressions)\n*   [MDX content](#mdx-content)\n    *   [Components](#components)\n    *   [Layout](#layout)\n*   [Integrations](#integrations)\n    *   [Bundlers](#bundlers)\n    *   [Build systems](#build-systems)\n    *   [Compilers](#compilers)\n    *   [Site generators](#site-generators)\n    *   [Hyperscript implementations (frameworks)](#hyperscript-implementations-frameworks)\n    *   [Runtime libraries](#runtime-libraries)\n*   [Guides](#guides)\n    *   [GitHub flavored markdown (GFM)](#github-flavored-markdown-gfm)\n    *   [Syntax highlighting](#syntax-highlighting)\n    *   [Math](#math)\n    *   [Frontmatter](#frontmatter)\n*   [Plugins](#plugins)\n*   [Types](#types)\n*   [Differences from `@mdx-js/mdx`](#differences-from-mdx-jsmdx)\n*   [Architecture](#architecture)\n*   [Security](#security)\n*   [Related](#related)\n*   [License](#license)\n\n## What is MDX?\n\nMDX is different things.\nThe term is sometimes used for a compiler, typically implying `@mdx-js/mdx`, but\nthere are more.\nFirst there was [`mdxc`][mdxc].\nThen came [`@mdx-js/mdx`][mdxjs].\nThere’s also [`mdsvex`][mdsvex].\nAnd now there’s **xdm** too.\n\nSometimes the term is used for a runtime/helper library.\n**xdm** has **no runtime**: it’s not needed!\n\nMost often the term is used for the format: markdown + JS(X) (there are some\n[caveats][]):\n\n```mdx\n## Hello, world!\n\n\u003cdiv className=\"note\"\u003e\n  \u003e Some notable things in a block quote!\n\u003c/div\u003e\n```\n\nSee?\nMost of markdown works!\nThose XML-like things are not HTML though: they’re JSX.\nNote that there are some differences in how JSX should be authored: for example,\nReact expects `className`, whereas Vue expects `class`.\nSee [§ MDX syntax][mdx-syntax] below for more on how the format works.\n\n## Use\n\nThis section describes how to use the API.\nSee [§ MDX syntax][mdx-syntax] on how the format works.\nSee [§ Integrations][integrations] on how to use **xdm** with Babel, esbuild,\nRollup, webpack, etc.\n\nSay we have an MDX document, `example.mdx`:\n\n```mdx\nexport const Thing = () =\u003e \u003c\u003eWorld!\u003c/\u003e\n\n# Hello, \u003cThing /\u003e\n```\n\nFirst, a rough idea of what the result will be.\nThe below is not the actual output, but it might help to form a mental model:\n\n```js\n/* @jsxRuntime automatic @jsxImportSource react */\n\nexport const Thing = () =\u003e \u003c\u003eWorld!\u003c/\u003e\n\nexport default function MDXContent() {\n  return \u003ch1\u003eHello, \u003cThing /\u003e\u003c/h1\u003e\n}\n```\n\nSome observations:\n\n*   The output is serialized JavaScript that still needs to be evaluated\n*   A comment is injected to configure how JSX is handled\n*   It’s a complete file with import/exports\n*   A component (`MDXContent`) is exported\n\nNow for how to get the actual output.\nAdd some code in `example.js` to compile `example.mdx` to JavaScript:\n\n```js\nimport {promises as fs} from 'node:fs'\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  const compiled = await compile(await fs.readFile('example.mdx'))\n  console.log(String(compiled))\n}\n```\n\nThe *actual* output of running `node example.js` is:\n\n```js\n/* @jsxRuntime automatic @jsxImportSource react */\nimport {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'\n\nexport const Thing = () =\u003e _jsx(_Fragment, {children: 'World!'})\n\nfunction MDXContent(props = {}) {\n  let {wrapper: MDXLayout} = props.components || ({})\n  return MDXLayout\n    ? _jsx(MDXLayout, Object.assign({}, props, {children: _jsx(_createMdxContent, {})}))\n    : _createMdxContent()\n  function _createMdxContent() {\n    let _components = Object.assign({h1: 'h1'}, props.components)\n    return _jsxs(_components.h1, {children: ['Hello, ', _jsx(Thing, {})]})\n  }\n}\n\nexport default MDXContent\n```\n\nSome more observations:\n\n*   JSX is compiled away to function calls and an import of React†\n*   The content component can be given `{components: {wrapper: MyLayout}}` to\n    wrap the whole content\n*   The content component can be given `{components: {h1: MyComponent}}` to use\n    something else for the heading\n\n† **xdm** is not coupled to React.\nYou can also use it with [Preact](#preact), [Vue](#vue), [Emotion](#emotion),\n[Theme UI](#theme-ui), etc.\n\nSee [§ MDX content][mdx-content] below on how to use the result.\n\n## API\n\n`xdm` exports the following identifiers:\n[`compile`][compile],\n[`compileSync`](#compilesyncfile-options),\n[`evaluate`][eval],\n[`evaluateSync`](#evaluatesyncfile-options),\n[`run`][run],\n[`runSync`](#runsyncfunctionbody-options), and\n[`createProcessor`](#createprocessoroptions).\nThere is no default export.\n\n`xdm/esbuild.js` exports a function as the default export that returns an\n[esbuild][] plugin.\n\n`xdm/rollup.js` exports a function as the default export that returns a\n[Rollup][] plugin.\n\n`xdm/webpack.cjs` exports a [webpack][] loader as the default export.\n\nThere is also `xdm/esm-loader.js` and `xdm/register.cjs`, see [👩‍🔬 Lab][lab]\nfor more info.\n\n### `compile(file, options?)`\n\nCompile MDX to JS.\n\n###### `file`\n\nMDX document to parse (`string`, [`Buffer`][buffer] in UTF-8, [`vfile`][vfile],\nor anything that can be given to `vfile`).\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nimport {VFile} from 'vfile'\nimport {compile} from 'xdm'\n\nawait compile(':)')\nawait compile(Buffer.from(':-)'))\nawait compile({path: 'path/to/file.mdx', value: '🥳'})\nawait compile(new VFile({path: 'path/to/file.mdx', value: '🤭'}))\n```\n\n\u003c/details\u003e\n\n###### `options.remarkPlugins`\n\nList of [remark plugins][remark-plugins], presets, and pairs.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nimport remarkFrontmatter from 'remark-frontmatter' // YAML and such.\nimport remarkGfm from 'remark-gfm' // Tables, strikethrough, tasklists, literal URLs.\n\nawait compile(file, {remarkPlugins: [remarkGfm]}) // One plugin.\nawait compile(file, {remarkPlugins: [[remarkFrontmatter, 'toml']]}) // A plugin with options.\nawait compile(file, {remarkPlugins: [remarkGfm, remarkFrontmatter]}) // Two plugins.\nawait compile(file, {remarkPlugins: [[remarkGfm, {singleTilde: false}], remarkFrontmatter]}) // Two plugins, first w/ options.\n```\n\n\u003c/details\u003e\n\n###### `options.rehypePlugins`\n\nList of [rehype plugins][rehype-plugins], presets, and pairs.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nimport rehypeKatex from 'rehype-katex' // Render math with KaTeX.\nimport remarkMath from 'remark-math' // Support math like `$so$`.\n\nawait compile(file, {remarkPlugins: [remarkMath], rehypePlugins: [rehypeKatex]})\n\nawait compile(file, {\n  remarkPlugins: [remarkMath],\n  // A plugin with options:\n  rehypePlugins: [[rehypeKatex, {throwOnError: true, strict: true}]]\n})\n```\n\n\u003c/details\u003e\n\n###### `options.recmaPlugins`\n\nList of recma plugins.\nThis is a new ecosystem, currently in beta, to transform\n[esast](https://github.com/syntax-tree/esast) trees (JavaScript).\n\n###### `options.remarkRehypeOptions`\n\nOptions to pass through to [`remark-rehype`][remark-rehype].\nThe option `allowDangerousHtml` will always be set to `true` and the MDX nodes\nare passed through.\nIn particular, you might want to pass `clobberPrefix`, `footnoteLabel`, and\n`footnoteBackLabel`.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nawait compile({value: '…'}, {remarkRehypeOptions: {clobberPrefix: 'comment-1'}})\n```\n\n\u003c/details\u003e\n\n###### `options.mdExtensions`\n\nList of markdown extensions, with dot (`string[]`, default: `['.md',\n'.markdown', '.mdown', '.mkdn', '.mkd', '.mdwn', '.mkdown', '.ron']`).\n\n###### `options.mdxExtensions`\n\nList of MDX extensions, with dot (`string[]`, default: `['.mdx']`).\nHas no effect in `compile` or `evaluate`, but does affect [esbuild][],\n[Rollup][], and the experimental ESM loader + register hook (see [👩‍🔬\nLab][lab]).\n\n###### `options.format`\n\nFormat the file is in (`'detect' | 'mdx' | 'md'`, default: `'detect'`).\n\n*   `'detect'` — use `'markdown'` for files with an extension in `mdExtensions`\n    and `'mdx'` otherwise\n*   `'mdx'` — treat file as [MDX][mdx-syntax]\n*   `'md'` — treat file as plain vanilla markdown\n\nThe format cannot be detected if a file is passed without a path or extension:\n`mdx` will be assumed.\nSo pass a full vfile (with `path`) or an object with a path.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\ncompile({value: '…'}) // Seen as MDX\ncompile({value: '…'}, {format: 'md'}) // Seen as markdown\ncompile({value: '…', path: 'readme.md'}) // Seen as markdown\n\n// Please do not use `.md` for MDX as other tools won’t know how to handle it.\ncompile({value: '…', path: 'readme.md'}, {format: 'mdx'}) // Seen as MDX\ncompile({value: '…', path: 'readme.md'}, {mdExtensions: []}) // Seen as MDX\n```\n\n\u003c/details\u003e\n\nThis option mostly affects [esbuild][] and [Rollup][] plugins, and the\nexperimental ESM loader + register hook (see [👩‍🔬 Lab][lab]), because in those\nit affects *which* files are “registered”:\n\n*   `format: 'mdx'` registers the extensions in `options.mdxExtensions`\n*   `format: 'md'` registers the extensions in `options.mdExtensions`\n*   `format: 'detect'` registers both lists of extensions\n\n###### `options.outputFormat`\n\nOutput format to generate (`'program' | 'function-body'`, default: `'program'`).\nIn most cases `'program'` should be used, as it results in a whole program.\nInternally, [`evaluate`][eval] uses `outputFormat: 'function-body'` to compile\nto code that can be `eval`ed with [`run`][run].\nIn some cases, you might want to do what `evaluate` does in separate steps\nyourself, such as when compiling on the server and running on the client.\n\nThe `'program'` format will use import statements to import the runtime (and\noptionally provider) and use an export statement to yield the `MDXContent`\ncomponent.\n\nThe `'function-body'` format will get the runtime (and optionally provider) from\n`arguments[0]`, rewrite export statements, and use a return statement to yield\nwhat was exported.\nNormally, this output format will throw on `import` (and `export … from`)\nstatements, but you can support them by setting\n[`options.useDynamicImport`][usedynamicimport].\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nA module `example.js`:\n\n```js\nimport {compile} from 'xdm'\n\nmain('export const no = 3.14\\n\\n# hi {no}')\n\nasync function main(code) {\n  console.log(String(await compile(code, {outputFormat: 'program'}))) // Default\n  console.log(String(await compile(code, {outputFormat: 'function-body'})))\n}\n```\n\n…yields:\n\n```js\nimport {Fragment as _Fragment, jsx as _jsx} from 'react/jsx-runtime'\nexport const no = 3.14\nfunction MDXContent(props = {}) { /* … */ }\nexport default MDXContent\n```\n\n```js\nconst {Fragment: _Fragment, jsx: _jsx} = arguments[0]\nconst no = 3.14\nfunction MDXContent(props = {}) { /* … */ }\nreturn {no, default: MDXContent}\n```\n\n\u003c/details\u003e\n\n###### `options.useDynamicImport`\n\nWhether to compile to dynamic import expressions (`boolean`, default: `false`).\nThis option applies when [`options.outputFormat`][outputformat] is\n`'function-body'`.\n\n**xdm** can turn import statements (`import x from 'y'`) into dynamic imports\n(`const {x} = await import('y')`).\nThis is useful because import statements only work at the top level of\nJavaScript modules, whereas `import()` is available inside function bodies.\n\nWhen you turn `useDynamicImport` on, you should probably set [`options.baseUrl`][baseurl] too.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nSay we have a couple modules:\n\n```js\n// meta.js:\nexport const title = 'World'\n\n// numbers.js:\nexport const no = 3.14\n\n// example.js:\nimport {compileSync} from 'xdm'\n\nconst code = `import {name} from './meta.js'\nexport {no} from './numbers.js'\n\n# hi {name}!`\n\nconsole.log(String(compileSync(code, {outputFormat: 'function-body', useDynamicImport: true})))\n```\n\n…now running `node example.js` yields:\n\n```js\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0]\nconst {name} = await import('./meta.js')\nconst {no} = await import('./numbers.js')\nfunction MDXContent(props = {}) { /* … */ }\nreturn {no, default: MDXContent}\n```\n\n\u003c/details\u003e\n\n###### `options.baseUrl`\n\nResolve relative `import` (and `export … from`) from this URL (`string?`,\nexample: `import.meta.url`).\n\nRelative specifiers are non-absolute URLs that start with `/`, `./`, or `../`.\nFor example: `/index.js`, `./folder/file.js`, or `../main.js`.\n\nThis option is useful when code will run in a different place.\nOne example is when `.mdx` files are in path *a* but compiled to path *b* and\nimports should run relative the path *b*.\nAnother example is when evaluating code, whether in Node or a browser.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nSay we have a module `example.js`:\n\n```js\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  const code = 'export {number} from \"./data.js\"\\n\\n# hi'\n  const baseUrl = 'https://a.full/url' // Typically `import.meta.url`\n  console.log(String(await compile(code, {baseUrl})))\n}\n```\n\n…now running `node example.js` yields:\n\n```js\nimport {Fragment as _Fragment, jsx as _jsx} from 'react/jsx-runtime'\nexport {number} from 'https://a.full/data.js'\nfunction MDXContent(props = {}) { /* … */ }\nexport default MDXContent\n```\n\n\u003c/details\u003e\n\n###### `options.development`\n\nWhether to add extra information to error messages in generated code\n(`boolean?`, default: `false`).\nThe default can be set to `true` in Node.js through environment variables: set\n`NODE_ENV=development`.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nSay we had some MDX that references a component that can be passed or provided\nat runtime:\n\n```mdx\n**Note**\u003cNoteIcon /\u003e: some stuff.\n```\n\nAnd a module to evaluate that:\n\n```js\nimport {promises as fs} from 'node:fs'\nimport * as runtime from 'react/jsx-runtime'\nimport {evaluate} from 'xdm'\n\nmain()\n\nasync function main() {\n  const path = 'example.mdx'\n  const value = await fs.readFile(path)\n  const MDXContent = (await evaluate({path, value}, runtime)).default\n  console.log(MDXContent())\n}\n```\n\nRunning that would normally (production) yield:\n\n```txt\nError: Expected component `NoteIcon` to be defined: you likely forgot to import, pass, or provide it.\n    at _missingMdxReference (eval at run (…/xdm/lib/run.js:18:10), \u003canonymous\u003e:27:9)\n    at _createMdxContent (eval at run (…/xdm/lib/run.js:18:10), \u003canonymous\u003e:15:20)\n    at MDXContent (eval at run (…/xdm/lib/run.js:18:10), \u003canonymous\u003e:9:9)\n    at main (…/example.js:11:15)\n```\n\nBut if we change add `development: true` to our example:\n\n```diff\n@@ -7,6 +7,6 @@ main()\n async function main() {\n   const path = 'example.mdx'\n   const value = await fs.readFile(path)\n-  const MDXContent = (await evaluate({path, value}, runtime)).default\n+  const MDXContent = (await evaluate({path, value}, {development: true, ...runtime})).default\n   console.log(MDXContent({}))\n }\n```\n\nAnd we’d run it again, we’d get:\n\n```txt\nError: Expected component `NoteIcon` to be defined: you likely forgot to import, pass, or provide it.\nIt’s referenced in your code at `1:9-1:21` in `example.mdx`\nprovide it.\n    at _missingMdxReference (eval at run (…/xdm/lib/run.js:18:10), \u003canonymous\u003e:27:9)\n    at _createMdxContent (eval at run (…/xdm/lib/run.js:18:10), \u003canonymous\u003e:15:20)\n    at MDXContent (eval at run (…/xdm/lib/run.js:18:10), \u003canonymous\u003e:9:9)\n    at main (…/example.js:11:15)\n```\n\n\u003c/details\u003e\n\n###### `options.SourceMapGenerator`\n\nThe `SourceMapGenerator` class from [`source-map`][source-map] (optional).\nWhen given, the resulting file will have a `map` field set to a source map (in\nobject form).\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nAssuming `example.mdx` from [§ Use][use] exists, then:\n\n```js\nimport {promises as fs} from 'node:fs'\nimport {SourceMapGenerator} from 'source-map'\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  const file = await compile(\n    {path: 'example.mdx', value: await fs.readFile('example.mdx')},\n    {SourceMapGenerator}\n  )\n\n  console.log(file.map)\n}\n```\n\n…yields:\n\n```js\n{\n  version: 3,\n  sources: ['example.mdx'],\n  names: ['Thing'],\n  mappings: ';;aAAaA,QAAQ;YAAQ;;;;;;;;iBAE3B',\n  file: 'example.mdx'\n}\n```\n\n\u003c/details\u003e\n\n###### `options.providerImportSource`\n\nPlace to import a provider from (`string?`, example: `'@mdx-js/react'`).\nUseful for runtimes that support context (React, Preact).\nThe provider must export a `useMDXComponents`, which is called to access an\nobject of components.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nIf `file` is the contents of `example.mdx` from [§ Use][use], then:\n\n```js\ncompile(file, {providerImportSource: '@mdx-js/react'})\n```\n\n…yields this difference:\n\n```diff\n /* @jsxRuntime automatic @jsxImportSource react */\n import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'\n+import {useMDXComponents as _provideComponents} from '@mdx-js/react'\n\n export const Thing = () =\u003e _jsx(_Fragment, {children: 'World!'})\n\n function MDXContent(props = {}) {\n-  let {wrapper: MDXLayout} = props.components || ({})\n+  let {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components)\n   return MDXLayout\n     ? _jsx(MDXLayout, Object.assign({}, props, {children: _jsx(_createMdxContent, {})}))\n     : _createMdxContent()\n   function _createMdxContent() {\n-    let _components = Object.assign({h1: 'h1'}, props.components)\n+    let _components = Object.assign({h1: 'h1'}, _provideComponents(), props.components)\n     return _jsxs(_components.h1, {children: ['Hello, ', _jsx(Thing, {})]})\n   }\n }\n\n export default MDXContent\n```\n\n\u003c/details\u003e\n\n###### `options.jsx`\n\nWhether to keep JSX (`boolean?`, default: `false`).\nThe default is to compile JSX away so that the resulting file is immediately\nrunnable.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nIf `file` is the contents of `example.mdx` from [§ Use][use], then:\n\n```js\ncompile(file, {jsx: true})\n```\n\n…yields this difference:\n\n```diff\n /* @jsxRuntime automatic @jsxImportSource react */\n-import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'\n\n-export const Thing = () =\u003e _jsx(_Fragment, {children: 'World!'})\n+export const Thing = () =\u003e \u003c\u003eWorld!\u003c/\u003e\n\n function MDXContent(props = {}) {\n   let {wrapper: MDXLayout} = props.components || ({})\n   return MDXLayout\n-    ? _jsx(MDXLayout, Object.assign({}, props, {children: _jsx(_createMdxContent, {})}))\n+    ? \u003cMDXLayout {...props}\u003e\u003c_createMdxContent /\u003e\u003c/MDXLayout\u003e\n     : _createMdxContent()\n   function _createMdxContent() {\n     let _components = Object.assign({h1: 'h1'}, props.components)\n-    return _jsxs(_components.h1, {children: ['Hello, ', _jsx(Thing, {})]})\n+    return \u003c_components.h1\u003e{\"Hello, \"}\u003cThing /\u003e\u003c/_components.h1\u003e\n   }\n }\n\n export default MDXContent\n```\n\n\u003c/details\u003e\n\n###### `options.jsxRuntime`\n\nJSX runtime to use (`'automatic' | 'classic'`, default: `'automatic'`).\nThe classic runtime compiles to calls such as `h('p')`, the automatic runtime\ncompiles to `import _jsx from '$importSource/jsx-runtime'\\n_jsx('p')`.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nIf `file` is the contents of `example.mdx` from [§ Use][use], then:\n\n```js\ncompile(file, {jsxRuntime: 'classic'})\n```\n\n…yields this difference:\n\n```diff\n-/* @jsxRuntime automatic @jsxImportSource react */\n-import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'\n+/* @jsxRuntime classic @jsx React.createElement @jsxFrag React.Fragment */\n+import React from 'react'\n\n-export const Thing = () =\u003e _jsx(_Fragment, {children: 'World!'})\n+export const Thing = () =\u003e React.createElement(React.Fragment, null, 'World!')\n…\n```\n\n\u003c/details\u003e\n\n###### `options.jsxImportSource`\n\nPlace to import automatic JSX runtimes from (`string?`, default: `'react'`).\nWhen in the `automatic` runtime, this is used to define an import for\n`_Fragment`, `_jsx`, and `_jsxs`.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nIf `file` is the contents of `example.mdx` from [§ Use][use], then:\n\n```js\ncompile(file, {jsxImportSource: 'preact'})\n```\n\n…yields this difference:\n\n```diff\n-/* @jsxRuntime automatic @jsxImportSource react */\n-import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'\n+/* @jsxRuntime automatic @jsxImportSource preact */\n+import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from 'preact/jsx-runtime'\n```\n\n\u003c/details\u003e\n\n###### `options.pragma`\n\nPragma for JSX (`string?`, default: `'React.createElement'`).\nWhen in the `classic` runtime, this is used as an identifier for function calls:\n`\u003cx /\u003e` to `React.createElement('x')`.\n\nYou should most probably define `pragmaFrag` and `pragmaImportSource` too when\nchanging this.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nIf `file` is the contents of `example.mdx` from [§ Use][use], then:\n\n```js\ncompile(file, {\n  jsxRuntime: 'classic',\n  pragma: 'preact.createElement',\n  pragmaFrag: 'preact.Fragment',\n  pragmaImportSource: 'preact/compat'\n})\n```\n\n…yields this difference:\n\n```diff\n-/* @jsxRuntime classic @jsx React.createElement @jsxFrag React.Fragment */\n-import React from 'react'\n+/* @jsxRuntime classic @jsx preact.createElement @jsxFrag preact.Fragment */\n+import preact from 'preact/compat'\n\n-export const Thing = () =\u003e React.createElement(React.Fragment, null, 'World!')\n+export const Thing = () =\u003e preact.createElement(preact.Fragment, null, 'World!')\n…\n```\n\n\u003c/details\u003e\n\n###### `options.pragmaFrag`\n\nPragma for JSX fragments (`string?`, default: `'React.Fragment'`).\nWhen in the `classic` runtime, this is used as an identifier for fragments: `\u003c\u003e`\nto `React.createElement(React.Fragment)`.\n\nSee `options.pragma` for an example.\n\n###### `options.pragmaImportSource`\n\nWhere to import the identifier of `pragma` from (`string?`, default: `'react'`).\nWhen in the `classic` runtime, this is used to import the `pragma` function.\nTo illustrate with an example: when `pragma` is `'a.b'` and `pragmaImportSource`\nis `'c'` this following will be generated: `import a from 'c'`.\n\nSee `options.pragma` for an example.\n\n###### Returns\n\n`Promise\u003cVFile\u003e` — Promise that resolves to the compiled JS as a [vfile][].\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nimport remarkPresetLintConsistent from 'remark-preset-lint-consistent' // Lint rules to check for consistent markdown.\nimport {reporter} from 'vfile-reporter'\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  const file = await compile('*like this* or _like this_?', {remarkPlugins: [remarkPresetLintConsistent]})\n  console.error(reporter(file))\n}\n```\n\nYields:\n\n```txt\n  1:16-1:27  warning  Emphasis should use `*` as a marker  emphasis-marker  remark-lint\n\n⚠ 1 warning\n```\n\n\u003c/details\u003e\n\n### `compileSync(file, options?)`\n\nCompile MDX to JS.\nSynchronous version of `compile`.\nWhen possible please use the async `compile`.\n\n### `evaluate(file, options)`\n\n\u003e ☢️ **Danger**: It’s called **evaluate** because it `eval`s JavaScript.\n\nCompile and [run][] MDX.\nWhen possible, please use `compile`, write to a file, and then run with Node or\nbundle with [esbuild][]/[Rollup][]/[webpack][].\nBut if you trust your content, `evaluate` can work.\n\nTypically, `import` (or `export … from`) do not work here.\nThey can be compiled to dynamic `import()` by passing\n[`options.useDynamicImport`][usedynamicimport].\n\n###### `file`\n\nSee [`compile`][compile].\n\n###### `options`\n\nMost options are the same as [`compile`][compile], with the following\nexceptions:\n\n*   `providerImportSource` is replaced by `useMDXComponents`\n*   `jsx*` and `pragma*` options are replaced by `jsx`, `jsxs`, and `Fragment`\n*   `outputFormat` is set to `function-body`\n\n###### `options.jsx`\n\n###### `options.jsxs`\n\n###### `options.Fragment`\n\nThese three options are required.\nThey come from an automatic JSX runtime that you must import yourself.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nimport * as runtime from 'react/jsx-runtime'\n\nconst {default: Content} = await evaluate('# hi', {...runtime, ...otherOptions})\n```\n\n\u003c/details\u003e\n\n###### `options.useMDXComponents`\n\nNeeded if you want to support a provider.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\nimport * as provider from '@mdx-js/react'\nimport * as runtime from 'react/jsx-runtime'\n\nconst {default: Content} = await evaluate('# hi', {...provider, ...runtime, ...otherOptions})\n```\n\n\u003c/details\u003e\n\n###### Returns\n\n`Promise\u003cModule\u003e` — Promise that resolves to something that looks a bit like a\nmodule: an object with a `default` field set to the component and anything else\nthat was exported from the MDX file available too.\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nAssuming the contents of `example.mdx` from [§ Use][use] was in `file`, then:\n\n```js\nimport * as runtime from 'react/jsx-runtime'\nimport {evaluate} from 'xdm'\n\nconsole.log(await evaluate(file, {...runtime}))\n```\n\n…yields:\n\n```js\n{Thing: [Function: Thing], default: [Function: MDXContent]}\n```\n\n\u003c/details\u003e\n\n### `evaluateSync(file, options)`\n\n\u003e ☢️ **Danger**: It’s called **evaluate** because it `eval`s JavaScript.\n\nCompile and run MDX.\nSynchronous version of [`evaluate`][eval].\nWhen possible please use the async `evaluate`.\n\n### `run(functionBody, options)`\n\n\u003e ☢️ **Danger**: This `eval`s JavaScript.\n\nRun MDX compiled as [`options.outputFormat: 'function-body'`][outputformat].\n\n###### `options`\n\nYou can pass `jsx`, `jsxs`, and `Fragment` from an automatic JSX runtime as\n`options`.\nYou can pass `useMDXComponents` from a provider in options as well if the MDX\nis compiled with `options.providerImportSource: '#'` (the exact value of this\noption doesn’t matter).\nAll other options have to be passed to `compile` instead.\n\n###### Returns\n\n`Promise\u003cModule\u003e` — See `evaluate`\n\n\u003cdetails\u003e\n\u003csummary\u003eExample\u003c/summary\u003e\n\nOn the server:\n\n```js\nimport {compile} from 'xdm'\n\nconst code = String(await compile('# hi', {outputFormat: 'function-body'}))\n```\n\nOn the client:\n\n```js\nimport {run} from 'xdm'\nimport * as runtime from 'react/jsx-runtime'\n\nconst code = '' // To do: get `code` from server somehow.\n\nconst {default: Content} = await run(code, runtime)\n```\n\n…yields:\n\n```js\n[Function: MDXContent]\n```\n\n\u003c/details\u003e\n\n### `runSync(functionBody, options)`\n\n\u003e ☢️ **Danger**: This `eval`s JavaScript.\n\nRun MDX.\nSynchronous version of [`run`][run].\nWhen possible please use the async `run`.\n\n### `createProcessor(options)`\n\nCreate a unified processor to compile MDX to JS.\nHas the same options as [`compile`][compile], but returns a configured\n[`processor`](https://github.com/unifiedjs/unified#processor).\n\nNote that `format: 'detect'` does not work here: only `'md'` or `'mdx'` are\nallowed (and `'mdx'` is the default).\n\n## 👩‍🔬 Lab\n\nThis section describes experimental features!\nThese do not adhere to semver and could break at any time!\n\n### Importing `.mdx` files directly\n\n[ESM loaders](https://nodejs.org/api/esm.html#esm_loaders) are an experimental\nfeature in Node, slated to change.\nStill, they let projects “hijack” imports, to do all sorts of fancy things!\n**xdm** comes with experimental support for importing `.mdx` files with\non-the-fly compilation, using `xdm/esm-loader.js`:\n\nAssuming `example.mdx` from [§ Use][use] exists, and our module `example.js`\nlooks as follows:\n\n```js\nimport {renderToStaticMarkup} from 'react-dom/server'\nimport React from 'react'\nimport Content from './example.mdx'\n\nconsole.log(renderToStaticMarkup(React.createElement(Content)))\n```\n\nRunning that with:\n\n```sh\nnode --experimental-loader=xdm/esm-loader.js example.js\n```\n\n…yields:\n\n```html\n\u003ch1\u003eHello, World!\u003c/h1\u003e\n```\n\nTo pass options, you can make your own loader, such as this `my-loader.js`:\n\n```js\nimport {createLoader} from 'xdm/esm-loader.js'\n\n// Load is for Node 17+, the rest for 12-16.\nconst {load, getFormat, transformSource} = createLoader(/* Options… */)\n\nexport {load, getFormat, transformSource}\n```\n\nWhich can then be used with `node --experimental-loader=./my-loader.js`.\n\nNode itself does not yet support multiple loaders, but it is possible to combine\nmultiple loaders with\n[`@node-loader/core`](https://github.com/node-loader/node-loader-core).\n\n### Requiring `.mdx` files directly\n\n[`require.extensions`](https://nodejs.org/api/modules.html#modules_require_extensions)\nis a deprecated feature in Node.\nStill, it lets projects “hijack” `require` calls to do fancy things.\n**xdm** comes with support for requiring `.mdx` files with on-the-fly\nevaluation, using `xdm/register.cjs`:\n\nAssuming `example.mdx` from [§ Use][use] exists, and our script `example.cjs`\nlooks as follows:\n\n```js\nconst React = require('react')\nconst {renderToStaticMarkup} = require('react-dom/server')\nconst Content = require('./example.mdx')\n\nconsole.log(renderToStaticMarkup(React.createElement(Content)))\n```\n\nRunning that with:\n\n```sh\nnode -r xdm/register.cjs example.cjs\n```\n\n…yields:\n\n```html\n\u003ch1\u003eHello, World!\u003c/h1\u003e\n```\n\nTo pass options, you can make your own hook, such as this `my-hook.cjs`:\n\n```js\n'use strict'\n\nconst register = require('xdm/lib/integration/require.cjs')\n\nregister({/* Options… */})\n```\n\nWhich can then be used with `node -r ./my-hook.cjs`.\n\nThe register hook uses [`evaluateSync`][eval].\nThat means `import` (and `export … from`) are not supported when requiring\n`.mdx` files.\n\n### Importing `.md` and `.mdx` files from the web in esbuild\n\n\u003e ⚠️ Note that this includes remote code in your bundle.\n\u003e Make sure you trust it!\n\u003e See [§ Security][security] for more info.\n\nWhen passing `allowDangerousRemoteMdx` to the esbuild loader, MD(X) and JS files\ncan be imported from `http:` and `https:` urls.\nTake this `index.mdx` file:\n\n```jsx\nimport Readme from 'https://raw.githubusercontent.com/wooorm/xdm/main/readme.md'\n\nEmbed the xdm readme like so:\n\n\u003cReadme /\u003e\n```\n\nAnd a module `build.js`:\n\n```js\nimport xdm from 'xdm/esbuild.js'\nimport esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['index.mdx'],\n  outfile: 'output.js',\n  format: 'esm',\n  plugins: [xdm({allowDangerousRemoteMdx: true, /* Other options… */})]\n})\n```\n\nRunning that (`node build.js`) and evaluating `output.js` (depends on how you\nevaluate React stuff) would give:\n\n```jsx\n\u003cp\u003eEmbed the xdm readme like so:\u003c/p\u003e\n\u003ch1\u003exdm\u003c/h1\u003e\n{/* … */}\n\u003cp\u003e\u003ca href=\"https://github.com/wooorm/xdm/blob/main/license\"\u003eMIT\u003c/a\u003e © …\u003c/p\u003e\n```\n\n## MDX syntax\n\n\u003e **Note**!\n\u003e You don’t have to use this syntax.\n\u003e Or use it always.\n\u003e With [`format`][format], you can opt-in gradually or not at all.\n\nThe MDX syntax is a mix between markdown and JSX.\nMarkdown often feels more natural to type than HTML (or JSX) for the common\nthings (like emphasis, headings).\nJSX is an extension to JavaScript that *looks* like HTML but makes it convenient\nto use components (reusable things).\nSee [this description](https://github.com/micromark/mdx-state-machine#71-syntax)\nfor a more formal description of the syntax.\n\nThis gives us something along the lines of [literate programming][lit].\n\nMDX also gives us an odd mix of two languages: markdown is whitespace sensitive\nand forgiving (what you type may not “work”, but it won’t crash) whereas\nJavaScript is whitespace **insensitive** and **does** crash on typos.\nWeirdly enough they combine pretty well!\n\nIt’s important to know markdown\n([see this cheatsheet and tutorial](https://commonmark.org/help/) for help)\nand have experience with JavaScript (specifically\n[JSX](https://facebook.github.io/jsx/)) to write (and enjoy writing) MDX.\n\nSome common gotchas with writing MDX are\n[documented here](https://github.com/micromark/mdx-state-machine#74-common-mdx-gotchas).\n\n### Markdown\n\nMost of markdown ([CommonMark][]) works:\n\n````mdx\n# Heading (rank 1)\n## Heading 2\n### 3\n#### 4\n##### 5\n###### 6\n\n\u003e Block quote\n\n* Unordered\n* List\n\n1. Ordered\n2. List\n\nA paragraph, introducing a thematic break:\n\n***\n\n```js\nsome.code()\n```\n\na [link](https://example.com), an ![image](./image.png), some *emphasis*,\nsomething **strong**, and finally a little `code()`.\n````\n\nSome other features often used with markdown are:\n\n*   **GFM** — autolink literals, strikethrough, tables, tasklists\n    ([see guide below](#github-flavored-markdown-gfm))\n*   **Frontmatter** — YAML\n    ([see guide below](#frontmatter))\n*   **Math**\n    ([see guide below](#math))\n*   **Syntax highlighting**\n    ([see guide below](#syntax-highlighting))\n\nThere are many more things possible by configuring\n[remark plugins][remark-plugins] and [rehype plugins][rehype-plugins].\n\nThere are also a couple specific remark/rehype/recma plugins that work with\nxdm: see [plugins][].\n\n#### Caveats\n\nSome markdown features don’t work in MDX:\n\n```mdx\nIndented code works in markdown, but not in MDX:\n\n    console.log(1) // this is a paragraph in MDX!\n\nThe reason for that is so that you can nicely indent your components.\n\nA different one is “autolinks”:\n\n\u003csvg:rect\u003e and \u003cadmin@example.com\u003e are links in markdown, but they crash xdm.\nThe reason is that they look a lot like JSX components, and we prefer being unambiguous.\nIf you want links, use [descriptive text](https://and-the-link-here.com).\n\nHTML doesn’t work, because MDX has JSX instead (see next section).\n\nAnd you must escape less than (`\u003c`) and opening braces (`{`) like so: \\\u003c or \\{.\n```\n\nMore on this is\n[documented here](https://github.com/micromark/mdx-state-machine#72-deviations-from-markdown).\n\n### JSX\n\nMost of JSX works.\nHere’s some that looks a lot like HTML (but is JSX):\n\n```js\n\u003ch1\u003eHeading!\u003c/h1\u003e\n\n\u003cabbr title=\"HyperText Markup Language\"\u003eHTML\u003c/abbr\u003e is a lovely language.\n\n\u003csection\u003e\n  And here is *markdown* in **JSX**!\n\u003c/section\u003e\n```\n\nYou can also use components, but note that you must either define them locally\nor pass them in later (see [§ MDX content][mdx-content]):\n\n```js\n\u003cMyComponent id=\"123\" /\u003e\n\nOr access the `thisOne` component on the `myComponents` object: \u003cmyComponents.thisOne /\u003e\n\n\u003cComponent\n  open\n  x={1}\n  label={'this is a string, *not* markdown!'}\n  icon={\u003cIcon /\u003e}\n/\u003e\n```\n\nMore on this is\n[documented here](https://github.com/micromark/mdx-state-machine#73-deviations-from-jsx).\n\n### ESM\n\nTo define things from within MDX, use ESM:\n\n```js\nimport {External} from './some/place.js'\n\nexport const Local = props =\u003e \u003cspan style={{color: 'red'}} {...props} /\u003e\n\nAn \u003cExternal /\u003e component and \u003cLocal\u003ea local component\u003c/Local\u003e.\n```\n\nESM can also be used for other things:\n\n```js\nimport {MyChart} from './chart-component.js'\nimport data from './population.js'\nexport const pi = 3.14\n\n\u003cMyChart data={data} label={'Something with ' + pi} /\u003e\n```\n\n### Expressions\n\nBraces can be used to embed JavaScript expressions in MDX:\n\n```mdx\nexport const pi = 3.14\n\nTwo 🍰 is: {pi * 2}\n```\n\nExpressions can be empty or contain just a comment:\n\n```mdx\n{/* A comment! */}\n```\n\n## MDX content\n\nAll content (headings, paragraphs, etc) you write are exported as the default\nexport from a compiled MDX file as a component.\n\nIt’s possible to pass props in.\nThe special prop `components` is used to determine how to render components.\nThis includes both JSX and markdown syntax.\nSay we have a `message.mdx` file:\n\n```mdx\n# Hello, *\u003cPlanet /\u003e*!\n\nRemember when we first met in {props.year}?\n```\n\nThis file could be imported from JavaScript and passed components like so:\n\n```js\nimport Message from './message.mdx' // Assumes an integration is used to compile MDX -\u003e JS.\n\n\u003cMessage components={{Planet: () =\u003e 'Venus'}} year={1962} /\u003e\n```\n\nYou can also change the things that come from markdown:\n\n```js\n\u003cMessage\n  components={{\n    // Map `h1` (`# heading`) to use `h2`s.\n    h1: 'h2',\n    // Rewrite `em`s (`*like so*`) to `i` with a red foreground color.\n    em: (props) =\u003e \u003ci style={{color: 'red'}} {...props} /\u003e,\n    // Pass a layout (using the special `'wrapper'` key).\n    wrapper: ({components, ...props}) =\u003e \u003cmain {...props} /\u003e,\n    // Pass a component.\n    Planet: () =\u003e 'Venus'\n  }}\n  year={1962}\n/\u003e\n```\n\n### Components\n\nThe following keys can be passed in `components`:\n\n*   HTML equivalents for the things you write with markdown (such as `h1` for\n    `# heading`)**†**\n*   `wrapper`, which defines the layout (but local layout takes precedence)\n*   `*` anything else that is a valid JavaScript identifier (`foo`,\n    `Components`, `_`, `$x`, `a1`) for the things you write with JSX (like\n    `\u003cSo /\u003e` or `\u003clike.so /\u003e`, note that locally defined components take\n    precedence)**‡**\n\n**†** Normally, in markdown, those are: `a`, `blockquote`, `br`, `code`, `em`,\n`h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `hr`, `img`, `li`, `ol`, `p`, `pre`,\n`strong`, and `ul`.\nWith [`remark-gfm`][gfm] ([see guide below](#github-flavored-markdown-gfm)), you\ncan also use: `del`, `section`, `sup`, `table`, `tbody`, `td`, `th`, `thead`,\nand `tr`.\nOther remark plugins that add support for new constructs and advertise that they\nwork with rehype, will also work with **xdm**.\n\n**‡** The rules for whether a name in JSX (`x` in `\u003cx\u003e`) is a literal tag name\nor not, are as follows:\n\n*   If there’s a dot, it’s a member expression (`\u003ca.b\u003e` -\u003e `h(a.b)`)\n*   Otherwise, if the name is not a valid identifier, it’s a literal (`\u003ca-b\u003e` -\u003e\n    `h('a-b')`)\n*   Otherwise, if it starts with a lowercase, it’s a literal (`\u003ca\u003e` -\u003e `h('a')`)\n*   Otherwise, it’s an identifier (`\u003cA\u003e` -\u003e `h(A)`)\n\n### Layout\n\nLayouts are components that wrap the whole content.\nThey can be defined from within MDX using a default export:\n\n```js\nexport default function Layout({children}) {\n  return \u003cmain\u003e{children}\u003c/main\u003e;\n}\n\nAll the things.\n```\n\nThe layout can also be imported and *then* exported with an `export … from`:\n\n```js\nexport {Layout as default} from './components.js'\n```\n\nThe layout can also be passed as `components.wrapper` (but a local one takes\nprecedence).\n\n## Integrations\n\n### Bundlers\n\n#### esbuild\n\nInstall `xdm` and use `xdm/esbuild.js`.\nAdd something along these lines to your `build` call:\n\n```js\nimport xdm from 'xdm/esbuild.js'\nimport esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['index.mdx'],\n  outfile: 'output.js',\n  format: 'esm',\n  plugins: [xdm({/* Options… */})]\n})\n```\n\nesbuild takes care of turning modern JavaScript features into syntax that works\nwherever you want it to.\nNo Babel needed.\nSee esbuild’s docs for more info.\n\n`options` are the same as from [`compile`][compile] with the addition of:\n\n###### `options.allowDangerousRemoteMdx`\n\nWhether to allow importing from `http:` and `https:` URLs (`boolean`, default:\n`false`).\nSee [§ Importing `.md` and `.mdx` files from the web in\nesbuild][import-from-web].\n\n\u003e ⚠️ Note that this evaluates any JavaScript and MDX found over the wire!\n\n#### Rollup\n\nInstall `xdm` and use `xdm/rollup.js`.\nAdd something along these lines to your `rollup.config.js`:\n\n```js\nimport path from 'node:path'\nimport xdm from 'xdm/rollup.js'\n\nexport default {\n  // …\n  plugins: [\n    // …\n    xdm({/* Options… */})\n  ]\n}\n```\n\nIf you use modern JavaScript features you might want to use Babel through\n[`@rollup/plugin-babel`](https://github.com/rollup/plugins/tree/master/packages/babel)\nto compile to code that works:\n\n```js\n// …\nimport {babel} from '@rollup/plugin-babel'\n\nexport default {\n  // …\n  plugins: [\n    // …\n    xdm({/* Options… */}),\n    babel({\n      // Also run on what used to be `.mdx` (but is now JS):\n      extensions: ['.js', '.jsx', '.es6', '.es', '.mjs', '.mdx', '.md'],\n      // Other options…\n    })\n  ]\n}\n```\n\nSource maps are supported.\nYou do not need to pass `options.SourceMapGenerator`.\n\n`options` are the same as from [`compile`][compile], with the additions of:\n\n###### `options.include`\n\n###### `options.exclude`\n\nList of [`picomatch`][pico] patterns to include and/or exclude\n(`string`, `RegExp`, `Array\u003cstring|RegExp\u003e`, default: `[]`).\n\n#### Webpack\n\nInstall `xdm` and use `xdm/webpack.cjs`.\nAdd something along these lines to your `webpack.config.js`:\n\n```js\nmodule.exports = {\n  module: {\n    // …\n    rules: [\n      // …\n      {test: /\\.mdx?$/, use: [{loader: 'xdm/webpack.cjs', options: {}}]}\n    ]\n  }\n}\n```\n\nSource maps are supported based on how you configure webpack.\nYou do not need to pass `options.SourceMapGenerator`.\n\nIf you use modern JavaScript features you might want to use Babel through\n[`babel-loader`](https://webpack.js.org/loaders/babel-loader/) to compile to\ncode that works:\n\n```js\n// …\nuse: [\n  // Note that Webpack runs right-to-left: `xdm` is used first, then\n  // `babel-loader`.\n  {loader: 'babel-loader', options: {}},\n  {loader: 'xdm/webpack.cjs', options: {}}\n]\n// …\n```\n\nNote that `webpack-cli` doesn’t support loaders in ESM directly or even\n*indirectly*.\nBecause `xdm` itself is ESM, this means the `xdm/webpack.cjs` loader (even\nthough it’s CJS) doesn’t work with `webpack-cli` (it does work when using the\nwebpack API).\nTo use this loader with `webpack-cli`, set the `DISABLE_V8_COMPILE_CACHE=1`\nenvironment variable.\nSee\n[GH-11](https://github.com/wooorm/xdm/issues/11#issuecomment-785043772) for\ndetails.\n\n```sh\nDISABLE_V8_COMPILE_CACHE=1 webpack\n```\n\n### Build systems\n\n#### Snowpack\n\n[Snowpack](https://www.snowpack.dev) uses [Rollup][] (for local files) which can\nbe extended.\nUnfortunately, `snowpack.config.js` is currently, ironically, CommonJS.\nSo figuring out a way to `import('xdm/rollup.js')` and use it in Snowpack, is\nleft as an exercise to the reader.\n\n#### Vite\n\n[Vite](https://vitejs.dev) supports [Rollup][] plugins directly in `plugins` in\nyour `vite.config.js`.\n\n#### WMR\n\n[WMR](https://github.com/preactjs/wmr) supports [Rollup][] plugins directly by\n[adding them to `plugins`](https://wmr.dev/docs/plugins/)\nin `wmr.config.mjs`.\n\n```js\nimport {defineConfig} from 'wmr'\nimport xdm from 'xdm/rollup.js'\n\nexport default defineConfig({\n  plugins: [\n    xdm({/* Options… */})\n  ]\n})\n```\n\nSee [§ Preact](https://github.com/wooorm/xdm#preact) if you want to use Preact.\n\n### Compilers\n\n#### Babel\n\nYou should probably use webpack or Rollup instead of Babel directly as that\ngives the neatest interface.\nIt is possible to use **xdm** in Babel and it’s fast, because it skips `xdm`\nserialization and Babel parsing, if Babel is used anyway.\n\nBabel does not support syntax extensions to its parser (it has “syntax” plugins\nbut those in fact turn certain flags on or off).\nIt does support setting a different parser.\nWhich in turn lets us choose whether to use the `xdm` or `@babel/parser`.\n\nThis Babel plugin, `plugin.js`:\n\n```js\nimport path from 'node:path'\nimport parser from '@babel/parser'\nimport estreeToBabel from 'estree-to-babel'\nimport {compileSync} from 'xdm'\n\nexport function babelPluginSyntaxMdx() {\n  // Tell Babel to use a different parser.\n  return {parserOverride: babelParserWithMdx}\n}\n\n// A Babel parser that parses `.mdx` files with xdm and passes any other things\n// through to the normal Babel parser.\nfunction babelParserWithMdx(value, options) {\n  if (\n    options.sourceFilename \u0026\u0026\n    /\\.mdx?$/.test(path.extname(options.sourceFilename))\n  ) {\n    // Babel does not support async parsers, unfortunately.\n    return compileSync(\n      {value, path: options.sourceFilename},\n      // Tell xdm to return a Babel tree instead of serialized JS.\n      {recmaPlugins: [recmaBabel]}\n    ).result\n  }\n\n  return parser.parse(value, options)\n}\n\n// A “recma” plugin is a unified plugin that runs on the estree (used by xdm\n// and much of the JS ecosystem but not Babel).\n// This plugin defines `'estree-to-babel'` as the compiler, which means that\n// the resulting Babel tree is given back by `compileSync`.\nfunction recmaBabel() {\n  Object.assign(this, {Compiler: estreeToBabel})\n}\n```\n\nCan be used like so with the Babel API:\n\n```js\nimport babel from '@babel/core'\nimport {babelPluginSyntaxMdx} from './plugin.js'\n\n// Note that a filename must be set for our plugin to know it’s MDX instead of JS.\nawait babel.transformAsync(file, {filename: 'example.mdx', plugins: [babelPluginSyntaxMdx]})\n```\n\n### Site generators\n\n#### Create React App (CRA)\n\nCreate a new app with [CRA](https://github.com/facebook/create-react-app) and\nchange directory to enter it:\n\n```sh\nnpx create-react-app my-app\ncd my-app\n```\n\nInstall `xdm` as a dev dependency:\n\n```sh\nyarn add xdm --dev\n```\n\nNow we can add our MDX content.\nCreate an MDX file `Content.mdx` in the `src/` folder:\n\n```mdx\nexport const Box = () =\u003e (\n  \u003cdiv style={{padding: 20, backgroundColor: 'tomato'}} /\u003e\n)\n\n# Hello, world!\n\nThis is **markdown** with \u003cspan style={{color: \"red\"}}\u003eJSX\u003c/span\u003e: MDX!\n\n\u003cBox /\u003e\n```\n\nTo use that content in the app, replace the contents of `App.js` in the `src/`\nfolder with:\n\n```js\n/* eslint-disable import/no-webpack-loader-syntax */\nimport Content from '!xdm/webpack.cjs!./Content.mdx'\n\nexport default function App() {\n  return \u003cContent /\u003e\n}\n```\n\nDone!\nTo start the development server run:\n\n```sh\nyarn start\n```\n\n#### Next.js\n\nNext uses webpack.\nInstall `xdm` and extend\n[Next’s config](https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config)\nin a `next.config.js` file like so:\n\n```js\nmodule.exports = {\n  // Support MDX files as pages:\n  pageExtensions: ['mdx', 'md', 'tsx', 'ts', 'jsx', 'js'],\n  // Support loading `.mdx`:\n  webpack(config) {\n    config.module.rules.push({\n      test: /\\.mdx?$/,\n      use: [{loader: 'xdm/webpack.cjs', options: {/* Options… */}}]\n    })\n\n    return config\n  }\n}\n```\n\n### Hyperscript implementations (frameworks)\n\n#### React\n\nWorks out of the box.\n\n\u003e What about **React server components**?\n\u003e\n\u003e While they are currently alpha and not shipping soon, there is an\n\u003e [experimental demo](https://wooorm.com/server-components-mdx-demo/)\n\u003e combining **xdm** with RSC.\n\nYou can set `providerImportSource` to `'@mdx-js/react'` (which has to be\ninstalled) to support context-based components passing.\n\n```js\nimport {MDXProvider} from '@mdx-js/react'\nimport Post from './post.mdx' // Assumes an integration is used to compile MDX -\u003e JS.\n\n\u003cMDXProvider components={{em: props =\u003e \u003ci {...props} /\u003e}}\u003e\n  \u003cPost /\u003e\n\u003c/MDXProvider\u003e\n```\n\nBut the above can also be written without configuring and importing a provider:\n\n```js\nimport Post from './post.mdx'\n\n\u003cPost components={{em: props =\u003e \u003ci {...props} /\u003e}} /\u003e\n```\n\n#### Preact\n\nDefine a different import source in [options][compile]:\n\n```js\ncompile(file, {jsxImportSource: 'preact'})\n```\n\nYou can set `providerImportSource` to `'@mdx-js/preact'` (which has to be\ninstalled) to support context-based components passing.\nSee React above for more information (but use `@mdx-js/preact`).\n\n#### Svelte\n\nUse [mdsvex][]!\n\n#### Vue\n\nUse Vue 3, which adds support for functional components and fragments, two\nfeatures heavily used in MDX.\n\nVue has a special way to compile JSX: **xdm** can’t do it but Babel can.\nTell `xdm` to keep the JSX:\n\n```js\nconst jsx = String(await compile(file, {jsx: true}))\n```\n\nThen compile the JSX away with Babel and\n[`@vue/babel-plugin-jsx`](https://github.com/vuejs/jsx-next/tree/dev/packages/babel-plugin-jsx):\n\n```js\nimport babel from '@babel/core'\n\nconst js = (await babel.transformAsync(jsx, {plugins: ['@vue/babel-plugin-jsx']})).code\n```\n\nYou are probably already using [webpack][] and/or [Rollup][] with Vue.\nIf not directly, then perhaps through something like Vue CLI.\nIn which case, see the above sections on these tools for how to use them, but\nconfigure them as shown in this section to import `.mdx` files.\n\n### Runtime libraries\n\n#### Emotion\n\nDefine a different import source in [options][compile] at compile time:\n\n```js\ncompile(file, {jsxImportSource: '@emotion/react'})\n```\n\nOtherwise, Emotion is React based, so see the React section for more info.\n\n#### Theme UI\n\nTheme UI is a React-specific library that requires using context to access its\neffective components.\nThis can be done at the place where you’re using MDX content at runtime:\n\n```js\nimport {base} from '@theme-ui/preset-base'\nimport {components, ThemeProvider} from 'theme-ui'\nimport Post from './post.mdx' // Assumes an integration is used to compile MDX -\u003e JS.\n\n\u003cThemeProvider theme={base}\u003e\n  \u003cPost components={components} /\u003e\n\u003c/ThemeProvider\u003e\n```\n\nIf using a `providerImportSource` set to `'@mdx-js/react'` while compiling,\nTheme UI automatically injects its components into that context:\n\n```js\nimport {base} from '@theme-ui/preset-base'\nimport {ThemeProvider} from 'theme-ui'\nimport Post from './post.mdx'\n\n\u003cThemeProvider theme={base}\u003e\n  \u003cPost /\u003e\n\u003c/ThemeProvider\u003e\n```\n\nOtherwise, Theme UI is Emotion and React based, so see their sections for more\ninfo.\n\n## Guides\n\n### GitHub flavored markdown (GFM)\n\nTo support GFM (autolink literals, strikethrough, tables, and tasklists) use\n[`remark-gfm`](https://github.com/remarkjs/remark-gfm).\nSay we have an MDX file like this:\n\n```mdx\n# GFM\n\n## Autolink literals\n\nwww.example.com, https://example.com, and contact@example.com.\n\n## Footnote\n\nA note[^1]\n\n[^1]: Big note.\n\n## Strikethrough\n\n~one~ or ~~two~~ tildes.\n\n## Table\n\n| a | b  |  c |  d  |\n| - | :- | -: | :-: |\n\n## Tasklist\n\n* [ ] to do\n* [x] done\n```\n\nThen do something like this:\n\n```js\nimport {promises as fs} from 'node:fs'\nimport remarkGfm from 'remark-gfm'\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  console.log(\n    String(\n      await compile(await fs.readFile('example.mdx'), {remarkPlugins: [remarkGfm]})\n    )\n  )\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow equivalent JSX\u003c/summary\u003e\n\n```js\n\u003ch1\u003eGFM\u003c/h1\u003e\n\u003ch2\u003eAutolink literals\u003c/h2\u003e\n\u003cp\u003e\n  \u003ca href=\"http://www.example.com\"\u003ewww.example.com\u003c/a\u003e,\n  \u003ca href=\"https://example.com\"\u003ehttps://example.com\u003c/a\u003e, and\n  \u003ca href=\"mailto:contact@example.com\"\u003econtact@example.com\u003c/a\u003e.\n\u003c/p\u003e\n\u003ch2\u003eFootnote\u003c/h2\u003e\n\u003cp\u003eA note\u003csup\u003e\u003ca href=\"#user-content-fn-1\" id=\"user-content-fnref-1\" data-footnote-ref aria-describedby=\"footnote-label\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003ch2\u003eStrikethrough\u003c/h2\u003e\n\u003cp\u003e\n  \u003cdel\u003eone\u003c/del\u003e or \u003cdel\u003etwo\u003c/del\u003e tildes.\n\u003c/p\u003e\n\u003ch2\u003eTable\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003ea\u003c/th\u003e\n      \u003cth align=\"left\"\u003eb\u003c/th\u003e\n      \u003cth align=\"right\"\u003ec\u003c/th\u003e\n      \u003cth align=\"center\"\u003ed\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n\u003c/table\u003e\n\u003ch2\u003eTasklist\u003c/h2\u003e\n\u003cul className=\"contains-task-list\"\u003e\n  \u003cli className=\"task-list-item\"\u003e\n    \u003cinput type=\"checkbox\" disabled /\u003e to do\n  \u003c/li\u003e\n  \u003cli className=\"task-list-item\"\u003e\n    \u003cinput type=\"checkbox\" checked disabled /\u003e done\n  \u003c/li\u003e\n\u003c/ul\u003e\n\u003csection data-footnotes className=\"footnotes\"\u003e\n\u003ch2 id=\"footnote-label\" className=\"sr-only\"\u003eFootnotes\u003c/h2\u003e\n\u003col\u003e\n  \u003cli id=\"user-content-fn-1\"\u003e\n    \u003cp\u003e\n      Big note.\n      \u003ca href=\"#user-content-fnref-1\" data-footnote-backref className=\"data-footnote-backref\" aria-label=\"Back to content\"\u003e↩\u003c/a\u003e\n    \u003c/p\u003e\n  \u003c/li\u003e\n\u003c/ol\u003e\n\u003c/section\u003e\n```\n\n\u003c/details\u003e\n\n### Syntax highlighting\n\nThere are two ways to accomplish syntax highlighting: at compile time or at\nruntime.\nDoing it at compile time means much less code is sent down the wire (syntax\nhighlighting needs a *lot* of code).\nDoing it at runtime gives flexibility.\n\n#### Syntax highlighting at compile time\n\nUse either [`rehype-highlight`](https://github.com/rehypejs/rehype-highlight)\n(`highlight.js`) or [`@mapbox/rehype-prism`](https://github.com/mapbox/rehype-prism)\n(Prism) by doing something like this:\n\n```js\nimport rehypeHighlight from 'rehype-highlight'\nimport {compile} from 'xdm'\n\nmain(`~~~js\nconsole.log(1)\n~~~`)\n\nasync function main(code) {\n  console.log(\n    String(await compile(code, {rehypePlugins: [rehypeHighlight]}))\n  )\n}\n```\n\n…you still need to load a relevant style sheet.\n\n\u003cdetails\u003e\n\u003csummary\u003eShow equivalent JSX\u003c/summary\u003e\n\n```js\n\u003cpre\u003e\n  \u003ccode className=\"hljs language-js\"\u003e\n    \u003cspan className=\"hljs-built_in\"\u003econsole\u003c/span\u003e.log(\n    \u003cspan className=\"hljs-number\"\u003e1\u003c/span\u003e)\n  \u003c/code\u003e\n\u003c/pre\u003e\n```\n\n\u003c/details\u003e\n\n#### Syntax highlighting at run time\n\nUse for example\n[`react-syntax-highlighter`](https://github.com/react-syntax-highlighter/react-syntax-highlighter),\nby doing something like this:\n\n```js\nimport SyntaxHighlighter from 'react-syntax-highlighter'\nimport Post from './example.mdx' // Assumes an integration is used to compile MDX -\u003e JS.\n\n\u003cPost components={{code}} /\u003e\n\nfunction code({className, ...props}) {\n  const match = /language-(\\w+)/.exec(className || '')\n  return match\n    ? \u003cSyntaxHighlighter language={match[1]} PreTag=\"div\" {...props} /\u003e\n    : \u003ccode className={className} {...props} /\u003e\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eShow equivalent JSX\u003c/summary\u003e\n\n```js\n\u003cpre\u003e\n  \u003cdiv\n    className=\"language-js\"\n    style={{\n      display: 'block',\n      overflowX: 'auto',\n      padding: '0.5em',\n      background: '#F0F0F0',\n      color: '#444'\n    }}\n  \u003e\n    \u003ccode style={{whiteSpace: 'pre'}}\u003e\n      \u003cspan\u003econsole.\u003c/span\u003e\n      \u003cspan style={{color: '#397300'}}\u003elog\u003c/span\u003e\n      \u003cspan\u003e(\u003c/span\u003e\n      \u003cspan style={{color: '#880000'}}\u003e1\u003c/span\u003e\n      \u003cspan\u003e)\u003c/span\u003e\n    \u003c/code\u003e\n  \u003c/div\u003e\n\u003c/pre\u003e\n```\n\n\u003c/details\u003e\n\n#### Syntax highlighting with the `meta` field\n\nMarkdown supports a meta string for code:\n\n````markdown\n```js filename=\"index.js\"\nconsole.log(1)\n```\n````\n\nThis is a *hidden* part of markdown: it’s normally not rendered.\nBut as the above example shows, it’s a useful place to put some extra fields.\n\n**xdm** doesn’t know whether you’re handling code as a component or what the\nformat of that meta string is, so it defaults to how markdown handles it: `meta`\nis ignored.\n\nThe short answer is:\nuse [`remark-mdx-code-meta`](https://github.com/remcohaszing/remark-mdx-code-meta),\nit lets you type JSX attributes in the `meta` part and exposes them on the\n`pre` component.\n\nOr you can do it yourself, however you want, by writing a custom plugin to\ninterpret the `meta` field.\nFor example, it’s possible to pass that string as a prop by writing a rehype\nplugin:\n\n```js\nfunction rehypeMetaAsAttribute() {\n  return transform\n}\n\nfunction transform(tree) {\n  visit(tree, 'element', onelement)\n}\n\nfunction onelement(node) {\n  if (node.tagName === 'code' \u0026\u0026 node.data \u0026\u0026 node.data.meta) {\n    node.properties.meta = node.data.meta\n  }\n}\n```\n\nThis would yields the following JSX:\n\n```jsx\n\u003cpre\u003e\n  \u003ccode class=\"language-js\" meta='filename=\"index.js\"'\u003e\n    console.log(1)\n  \u003c/code\u003e\n\u003c/pre\u003e\n```\n\nNote that the `meta` attribute is not valid HTML, so make sure to handle `code`\nwith a component.\n\nThe meta string in this example looks a lot like HTML attributes.\nWhat if we wanted to parse that string and add each “attribute” as a prop?\nUsing the same rehype plugin as above, but with a different `onelement`\nfunction, that can be achieved:\n\n```js\nconst re = /\\b([-\\w]+)(?:=(?:\"([^\"]*)\"|'([^']*)'|([^\"'\\s]+)))?/g\n\n// …\n\nfunction onelement(node) {\n  let match\n\n  if (node.tagName === 'code' \u0026\u0026 node.data \u0026\u0026 node.data.meta) {\n    re.lastIndex = 0 // Reset regex.\n\n    while ((match = re.exec(node.data.meta))) {\n      node.properties[match[1]] = match[2] || match[3] || match[4] || ''\n    }\n  }\n}\n```\n\nThis would yields the following JSX:\n\n```jsx\n\u003cpre\u003e\n  \u003ccode class=\"language-js\" filename=\"index.js\"\u003e\n    console.log(1)\n  \u003c/code\u003e\n\u003c/pre\u003e\n```\n\nNote that the these added attributes are not valid HTML, so make sure to handle\n`code` with a component.\n\n### Math\n\nUse\n[`remark-math`](https://github.com/remarkjs/remark-math/tree/main/packages/remark-math)\nand either\n[`rehype-katex`](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex)\n(KaTeX) or\n[`rehype-mathjax`](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-mathjax)\n(MathJax) by doing something like this:\n\n```js\nimport rehypeKatex from 'rehype-katex'\nimport remarkMath from 'remark-math'\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  console.log(\n    String(\n      // You only need one backslash in an MDX file but because this is JS wrapping it,\n      // a double backslash is needed.\n      await compile('# $\\\\sqrt{a^2 + b^2}$', {\n        remarkPlugins: [remarkMath],\n        rehypePlugins: [rehypeKatex]\n      })\n    )\n  )\n}\n```\n\n…you still need to load a KaTeX style sheet when using `rehype-katex`.\n\n\u003cdetails\u003e\n\u003csummary\u003eShow equivalent JSX\u003c/summary\u003e\n\n```js\n\u003ch1\u003e\n  \u003cspan className=\"math math-inline\"\u003e\n    \u003cspan className=\"katex\"\u003e\n      \u003cspan className=\"katex-mathml\"\u003e\n        \u003cmath xmlns=\"http://www.w3.org/1998/Math/MathML\"\u003e…\u003c/math\u003e\n      \u003c/span\u003e\n      \u003cspan className=\"katex-html\" aria-hidden=\"true\"\u003e…\u003c/span\u003e\n    \u003c/span\u003e\n  \u003c/span\u003e\n\u003c/h1\u003e\n```\n\n\u003c/details\u003e\n\n### Frontmatter\n\nFrontmatter, typically in YAML format, is frequently combined with markdown.\nMDX comes with support for ESM (import/exports) which is a powerful dynamic\nalternative.\n\nSay we had this `post.mdx`:\n\n```mdx\nexport const name = 'World'\nexport const title = 'Hi, ' + name + '!'\n\n# {title}\n```\n\nUsed like so:\n\n```js\nimport * as Post from './post.mdx' // Assumes an integration is used to compile MDX -\u003e JS.\n\nconsole.log(Post.title) // Prints 'Hi, World!'\n```\n\nStill, you might prefer frontmatter because it lets you define data that can be\nextracted from files *without* (or before) compiling:\n\nSay our `post.mdx` with frontmatter looked like this:\n\n```mdx\n---\ntitle: Hi, World!\n---\n\n# Hi, World!\n```\n\nThen without compiling or evaluating that file the metadata can be accessed like\nso:\n\n```js\nimport {promises as fs} from 'node:fs'\nimport yaml from 'js-yaml'\n\nmain()\n\nasync function main() {\n  console.log(yaml.loadAll(await fs.readFile('example.mdx'))[0]) // Prints `{title: 'Hi, World!'}`\n}\n```\n\n`xdm` doesn’t understand YAML frontmatter by default but can understand it\nusing [`remark-frontmatter`](https://github.com/remarkjs/remark-frontmatter):\n\n```js\nimport {promises as fs} from 'node:fs'\nimport remarkFrontmatter from 'remark-frontmatter'\nimport {compile} from 'xdm'\n\nmain()\n\nasync function main() {\n  console.log(\n    await compile(await fs.readFile('example.mdx'), {\n      remarkPlugins: [remarkFrontmatter]\n    })\n  )\n}\n```\n\nNow it “works”: the frontmatter is ignored.\nBut it’s not available from *inside* the MDX.\nWhat if we wanted to use frontmatter from inside the MDX file too?\nLike so?\n\n```mdx\n---\ntitle: Hi, World!\n---\n\n# {frontmatter.title}\n```\n\nThat’s what\n[`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter)\ndoes.\n\n## Plugins\n\nxdm has several extension points:\n\n*   Components and a layout (wrapper) can be defined internally or passed at\n    runtime (see [§ MDX content][mdx-content])\n*   Plugins can hook into several stages of compilation ([remark\n    plugins][remark-plugins], [rehype plugins][rehype-plugins], and the new\n    recma plugins)\n\nThere are also a few of these extensions made specifically for MDX:\n\n###### Components\n\nNone yet!\n\n###### Plugins\n\n*   [`rehype-mdx-title`](https://github.com/remcohaszing/rehype-mdx-title)\n    — expose the page title as a string\n*   [`remark-mdx-code-meta`](https://github.com/remcohaszing/remark-mdx-code-meta)\n    — interpret the code `meta` field as JSX props\n*   [`remark-mdx-images`](https://github.com/remcohaszing/remark-mdx-images)\n    — change image sources to JavaScript imports\n*   [`remark-mdx-frontmatter`](https://github.com/remcohaszing/remark-mdx-frontmatter)\n    — change frontmatter (YAML) metadata to exports\n\n## Types\n\nThis package is fully typed with [TypeScript](https://www.typescriptlang.org).\n\nTo enable types for imported `.mdx`, `.md`, etcetera files, first make sure\nthe TypeScript `JSX` namespace is typed (such as by importing the `react`\ntypes).\nThen install `@types/mdx`, which adds types to import statements of supported\nfiles.\n\n```js\nimport Post from './post.mdx' // `Post` is now typed.\n```\n\n## Differences from `@mdx-js/mdx`\n\n**API** (build):\n\n*   Remove `skipExport` or `wrapExport` options\n*   Add support for automatic JSX runtime\n*   Add support for non-react classic runtime\n*   Add support for source maps\n*   Add `evaluate` instead of `runtime` package to eval MDX\n*   Remove JSX from output (by default)\n*   Default to automatic JSX runtime\n*   No [GFM by default](#github-flavored-markdown-gfm)\n\n**API** (run):\n\n*   No providers by default\n*   No runtime at all\n*   `export`s work in `evaluate`\n*   Add support for compiling import statements to dynamic import expressions\n*   Add support for resolving import/export sources\n\n**Input**:\n\n*   ± same as `main` branch of `@mdx-js/mdx`\n*   Fix JSX tags to prevent `\u003cp\u003e\u003ch1 /\u003e\u003c/p\u003e`\n*   Plain markdown can be loaded (`format: 'md'`)\n\n**Output**:\n\n*   No `isMDXContent` prop on the `MDXContent` component\n*   Missing components throw instead of warn\n*   Sandbox: when passing `components: {h1 = () =\u003e ...}` that component gets\n    used for `# heading` but not for `\u003ch1\u003eheading\u003c/h1\u003e`\n*   Local components (including layouts) precede over given components\n*   Remove support for passing `parent.child` combos (`ol.li`) for components\n*   Remove support for passing `inlineCode` component (use `pre` and/or `code`\n    instead)\n*   Support for import and exports in `evaluate`\n*   Fix a bug with encoding `\"` in attributes\n\n**Experiments**:\n\n*   Add support for `import Content from './file.mdx'` in Node\n*   Add support for `require('./file.mdx')` in Node\n*   Add support `allowDangerousRemoteMdx` in esbuild to load MD(X) from the web\n\n## Architecture\n\nTo understand what this project does, it’s very important to first understand\nwhat unified does: please read through the\n[`unifiedjs/unified`](https://github.com/unifiedjs/unified) readme (the part\nuntil you hit the API section is required reading).\n\n**xdm** is a unified pipeline — wrapped so that most folks don’t need to know\nabout unified:\n[`core.js#L76-L102`](https://github.com/wooorm/xdm/blob/main/lib/core.js#L58-L84).\nThe processor goes through these steps:\n\n1.  Parse MDX (serialized markdown with embedded JSX, ESM, and expressions)\n    to mdast (markdown syntax tree)\n2.  Transform through remark (markdown ecosystem)\n3.  Transform mdast to hast (HTML syntax tree)\n4.  Transform through rehype (HTML ecosystem)\n5.  Transform hast to esast (JS syntax tree)\n6.  Do the work needed to get a component\n7.  Transform through recma (JS ecosystem)\n8.  Serialize esast as JavaScript\n\nThe *input* is MDX (serialized markdown with embedded JSX, ESM, and\nexpressions).\nThe markdown is parsed with [`micromark`][micromark] and the embedded JS with\none of its extensions\n[`micromark-extension-mdxjs`](https://github.com/micromark/micromark-extension-mdxjs)\n(which in turn uses [acorn][]).\nThen [`mdast-util-from-markdown`](https://github.com/syntax-tree/mdast-util-from-markdown)\nand its extension\n[`mdast-util-mdx`](https://github.com/syntax-tree/mdast-util-mdx) are used to\nturn the results from the parser into a syntax tree:\n[mdast](https://github.com/syntax-tree/mdast).\n\nMarkdown is closest to the source format.\nThis is where [remark plugins][remark-plugins] come in.\nTypically, there shouldn’t be much going on here.\nBut perhaps you want to support GFM (tables and such) or frontmatter?\nThen you can add a plugin here: `remark-gfm` or `remark-frontmatter`,\nrespectively.\n\nAfter markdown, we go to [hast](https://github.com/syntax-tree/hast) (HTML).\nThis transformation is done by\n[`mdast-util-to-hast`](https://github.com/syntax-tree/mdast-util-to-hast).\nWait, why, what does HTML have to do with it?\nPart of the reason is that we care about HTML semantics: we want to know that\nsomething is an `\u003ca\u003e`, not whether it’s a link with a resource (`[text](url)`)\nor a reference to a defined link definition (`[text][id]\\n\\n[id]: url`).\nSo an HTML AST is *closer* to where we want to go.\nAnother reason is that there are many things folks need when they go MDX -\u003e JS,\nmarkdown -\u003e HTML, or even folks who only process their HTML -\u003e HTML: use cases\nother than xdm.\nBy having a single AST in these cases and writing a plugin that works on that\nAST, that plugin can supports *all* these use cases (for example,\n[`rehype-highlight`](https://github.com/rehypejs/rehype-highlight)\nfor syntax highlighting or\n[`rehype-katex`](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex)\nfor math).\nSo, this is where [rehype plugins][rehype-plugins] come in: most of the plugins,\nprobably.\n\nThen we go to JavaScript: [esast](https://github.com/syntax-tree/esast) (JS; an\nAST which is compatible with estree but looks a bit more like other unist ASTs).\nThis transformation is done by\n[`hast-util-to-estree`](https://github.com/syntax-tree/hast-util-to-estree).\nThis is a new ecosystem that does not have utilities or plugins yet.\nBut it’s where **xdm** does its thing: where it adds imports/exports, where it\ncompiles JSX away into `_jsx()` calls, and where it does the other cool things\nthat it provides.\n\nFinally, The output is serialized JavaScript.\nThat final step is done by [astring](https://github.com/davidbonnet/astring), a\nsmall and fast JS generator.\n\n## Security\n\nMDX is unsafe: it’s a programming language.\nYou might want to look into using `\u003ciframe\u003e`s with `sandbox`, but security is\nhard, and that doesn’t seem to be 100%.\nFor Node, [vm2](https://github.com/patriksimek/vm2) sounds interesting.\nBut you should probably also sandbox the whole OS (Docker?), perform rate\nlimiting, and make sure processes can be killed when taking too long.\n\n## Related\n\nA lot of things are going on in `xdm`: parsing markdown to a syntax tree,\nhandling JavaScript (and JS) inside that markdown, converting to an HTML syntax\ntree, converting *that* to a Js syntax tree, all the while running several\ntransforms, before finally serializing JavaScript.\n\nMost of the work is done by:\n\n*   [`micromark`][micromark]\n    — Handles parsing of markdown (CommonMark)\n*   [`acorn`][acorn]\n    — Handles parsing of JS (ECMAScript)\n*   [`unifiedjs.com`](https://unifiedjs.com)\n    — Ties it all together\n\n## License\n\n[MIT][license] © [Titus Wormer][author], Compositor, and Vercel, Inc.\n\n\u003c/details\u003e\n\n\u003c!-- Definitions --\u003e\n\n[build-badge]: https://github.com/wooorm/xdm/workflows/main/badge.svg\n\n[build]: https://github.com/wooorm/xdm/actions\n\n[coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/xdm.svg\n\n[coverage]: https://codecov.io/github/wooorm/xdm\n\n[downloads-badge]: https://img.shields.io/npm/dm/xdm.svg\n\n[downloads]: https://www.npmjs.com/package/xdm\n\n[size-badge]: https://img.shields.io/bundlephobia/minzip/xdm.svg\n\n[size]: https://bundlephobia.com/result?p=xdm\n\n[npm]: https://docs.npjs.com/cli/install\n\n[yarn]: https://classic.yarnpkg.com/docs/cli/add/\n\n[license]: license\n\n[author]: https://wooorm.com\n\n[buffer]: https://nodejs.org/api/buffer.html\n\n[mdxc]: https://github.com/jamesknelson/mdxc\n\n[mdxjs]: https://github.com/mdx-js/mdx\n\n[mdsvex]: https://www.github.com/pngwn/mdsvex\n\n[lit]: https://en.wikipedia.org/wiki/Literate_programming\n\n[commonmark]: https://commonmark.org\n\n[source-map]: https://github.com/mozilla/source-map\n\n[vfile]: https://github.com/vfile/vfile\n\n[remark-plugins]: https://github.com/remarkjs/remark/blob/main/doc/plugins.md#list-of-plugins\n\n[rehype-plugins]: https://github.com/rehypejs/rehype/blob/main/doc/plugins.md#list-of-plugins\n\n[remark-rehype]: https://github.com/remarkjs/remark-rehype\n\n[gfm]: https://github.com/remarkjs/remark-gfm\n\n[compile]: #compilefile-options\n\n[eval]: #evaluatefile-options\n\n[run]: #runfunctionbody-options\n\n[integrations]: #integrations\n\n[mdx-syntax]: #mdx-syntax\n\n[mdx-content]: #mdx-content\n\n[use]: #use\n\n[format]: #optionsformat\n\n[outputformat]: #optionsoutputformat\n\n[baseurl]: #optionsbaseurl\n\n[usedynamicimport]: #optionsusedynamicimport\n\n[esbuild]: #esbuild\n\n[rollup]: #rollup\n\n[webpack]: #webpack\n\n[caveats]: #caveats\n\n[plugins]: #plugins\n\n[micromark]: https://github.com/micromark/micromark\n\n[acorn]: https://github.com/acornjs/acorn\n\n[pico]: https://github.com/micromatch/picomatch#globbing-features\n\n[lab]: #-lab\n\n[import-from-web]: #importing-md-and-mdx-files-from-the-web-in-esbuild\n\n[security]: #security\n","funding_links":["https://github.com/sponsors/wooorm"],"categories":["JavaScript","编辑器相关"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwooorm%2Fxdm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwooorm%2Fxdm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwooorm%2Fxdm/lists"}