Structured Datamdxld
Compilation
Compile MDXLD documents to executable code
Compilation
mdxld can compile MDX documents to executable JavaScript/JSX code.
Basic Compilation
import { compile } from 'mdxld/compile'
const doc = parse(`---
title: Hello World
---
# Hello World
<Button onClick={() => alert('clicked')}>
Click me
</Button>
`)
const result = await compile(doc)
console.log(result.code)Options
interface CompileOptions {
/** Output JSX instead of React.createElement calls */
jsx?: boolean
/** JSX import source for automatic runtime */
jsxImportSource?: string
/** Remark plugins for markdown processing */
remarkPlugins?: Plugin[]
/** Rehype plugins for HTML processing */
rehypePlugins?: Plugin[]
/** Output format: 'function-body' or 'program' */
outputFormat?: 'function-body' | 'program'
/** Development mode (more detailed errors) */
development?: boolean
}Example Output
Input
---
title: Example
---
# Hello
This is **bold** text.Output (function-body)
function _createMdxContent(props) {
const _components = {
h1: "h1",
p: "p",
strong: "strong",
...props.components
}
return (
<>
<_components.h1>Hello</_components.h1>
<_components.p>
This is <_components.strong>bold</_components.strong> text.
</_components.p>
</>
)
}
export default function MDXContent(props = {}) {
return <_createMdxContent {...props} />
}Using Plugins
Remark Plugins
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
const result = await compile(doc, {
remarkPlugins: [
remarkGfm, // GitHub Flavored Markdown
remarkMath, // Math support
],
})Rehype Plugins
import rehypeHighlight from 'rehype-highlight'
import rehypeSlug from 'rehype-slug'
const result = await compile(doc, {
rehypePlugins: [
rehypeHighlight, // Syntax highlighting
rehypeSlug, // Add IDs to headings
],
})Runtime Execution
Browser
import * as runtime from 'react/jsx-runtime'
const result = await compile(doc, {
outputFormat: 'function-body',
})
const { default: Content } = await evaluate(result.code, runtime)
// Use in React
function Page() {
return <Content components={{ Button: MyButton }} />
}Server-Side
import { compile, run } from 'mdxld/compile'
import * as runtime from 'react/jsx-runtime'
const compiled = await compile(doc)
const { default: Content } = await run(compiled.code, runtime)
// Render to string
import { renderToString } from 'react-dom/server'
const html = renderToString(<Content />)Custom Components
const components = {
// Override default elements
h1: ({ children }) => <h1 className="text-4xl font-bold">{children}</h1>,
p: ({ children }) => <p className="my-4">{children}</p>,
// Custom components
Button: ({ children, onClick }) => (
<button
onClick={onClick}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
{children}
</button>
),
// Code blocks with syntax highlighting
code: ({ className, children }) => {
const language = className?.replace('language-', '')
return (
<SyntaxHighlighter language={language}>
{children}
</SyntaxHighlighter>
)
},
}
function Page() {
return <Content components={components} />
}Frontmatter Access
Access frontmatter data in your compiled output:
const result = await compile(doc, {
remarkPlugins: [
// Include frontmatter as export
() => (tree, file) => {
tree.children.unshift({
type: 'mdxjsEsm',
value: `export const frontmatter = ${JSON.stringify(doc.data)}`,
})
}
]
})
// In the compiled output
import Content, { frontmatter } from './compiled.js'
console.log(frontmatter.title) // 'Example'Error Handling
import { compile, CompileError } from 'mdxld/compile'
try {
const result = await compile(doc, { development: true })
} catch (error) {
if (error instanceof CompileError) {
console.error('Compilation failed:')
console.error(`Line ${error.line}, Column ${error.column}`)
console.error(error.message)
}
}Caching
import { compile } from 'mdxld/compile'
import { createHash } from 'crypto'
const cache = new Map()
async function compileWithCache(doc) {
const hash = createHash('md5')
.update(doc.content)
.update(JSON.stringify(doc.data))
.digest('hex')
if (cache.has(hash)) {
return cache.get(hash)
}
const result = await compile(doc)
cache.set(hash, result)
return result
}Integration with Bundlers
Vite
// vite.config.ts
import mdx from '@mdx-js/rollup'
export default {
plugins: [
mdx({
remarkPlugins: [],
rehypePlugins: [],
})
]
}Next.js
// next.config.js
import createMDX from '@next/mdx'
const withMDX = createMDX({
options: {
remarkPlugins: [],
rehypePlugins: [],
},
})
export default withMDX({
pageExtensions: ['js', 'jsx', 'md', 'mdx'],
})