mirror of
https://github.com/mdx-js/mdx.git
synced 2024-09-19 19:38:18 +03:00
Add guide on injecting components
This commit is contained in:
parent
f48d038b96
commit
a9f0c046bb
120
docs/guides/injecting-components.mdx
Normal file
120
docs/guides/injecting-components.mdx
Normal file
@ -0,0 +1,120 @@
|
||||
export const info = {
|
||||
author: [
|
||||
{github: 'wooorm', name: 'Titus Wormer', twitter: 'wooorm'}
|
||||
],
|
||||
modified: new Date('2023-10-24'),
|
||||
published: new Date('2023-10-24')
|
||||
}
|
||||
export const navSortSelf = 7
|
||||
|
||||
# Injecting components
|
||||
|
||||
This guide shows how to inject arbitrary components into MDX when it
|
||||
runs. {/* more */}
|
||||
It shows how the underlying features used by our providers (`@mdx-js/react`,
|
||||
`@mdx-js/preact`) and the [`mdx-components.tsx`][next-mdx-components] file
|
||||
supported by Next.js work,
|
||||
and how you can take advantage of that functionality yourself.
|
||||
|
||||
In many cases you do not need this,
|
||||
as you can pass components to MDX:
|
||||
|
||||
```mdx path="example.mdx"
|
||||
# Hello *<Planet />*
|
||||
```
|
||||
|
||||
You can pass `Planet` and say a component used instead of the `h1`:
|
||||
|
||||
```tsx path="example.jsx"
|
||||
import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS.
|
||||
|
||||
<Example
|
||||
components={{
|
||||
Planet() {
|
||||
return 'Pluto'
|
||||
},
|
||||
h1(props) {
|
||||
return <h2 {...props} />
|
||||
}
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
When you find yourself passing that `components` prop around a lot,
|
||||
you might want to look at an alternative.
|
||||
You might reach for our context based providers (`@mdx-js/react`,
|
||||
`@mdx-js/preact`),
|
||||
but context has performance downsides and context doesn’t always work (such as
|
||||
in RSC).
|
||||
|
||||
But first,
|
||||
how does component passing work?
|
||||
That can be illustrated by looking at the code generated by MDX for the above
|
||||
`example.mdx`.
|
||||
Here is a diff that shows what the example normally compiles to and what
|
||||
changes when `providerImportSource: 'xxx'` is passed:
|
||||
|
||||
```diff
|
||||
@@ -1,7 +1,13 @@
|
||||
import {jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
|
||||
+import {useMDXComponents as _provideComponents} from 'xxx'
|
||||
|
||||
function _createMdxContent(props) {
|
||||
- const _components = {em: 'em', h1: 'h1', ...props.components}
|
||||
+ const _components = {
|
||||
+ em: 'em',
|
||||
+ h1: 'h1',
|
||||
+ ..._provideComponents(),
|
||||
+ ...props.components
|
||||
+ }
|
||||
const {Planet} = _components
|
||||
if (!Planet) _missingMdxReference('Planet', true)
|
||||
return _jsxs(_components.h1, {
|
||||
@@ -10,7 +16,7 @@ function _createMdxContent(props) {
|
||||
}
|
||||
|
||||
export default function MDXContent(props = {}) {
|
||||
- const {wrapper: MDXLayout} = props.components || {}
|
||||
+ const {wrapper: MDXLayout} = {..._provideComponents(), ...props.components}
|
||||
return MDXLayout
|
||||
? _jsx(MDXLayout, {...props, children: _jsx(_createMdxContent, {...props})})
|
||||
: _createMdxContent(props)
|
||||
```
|
||||
|
||||
Observe that components have defaults (such as that `h1` will use `'h1'`) and
|
||||
that components are taken from `props.components`.
|
||||
What changes is an added call to `_provideComponents`,
|
||||
which refers to an `useMDXComponents` export from the module we specified
|
||||
(`xxx`).
|
||||
|
||||
We can use this interface to inject components from a file.
|
||||
In that file,
|
||||
we need a `useMDXComponents` function that returns our components.
|
||||
|
||||
```tsx path="mdx-components.js"
|
||||
/** @returns {import('mdx/types.js').MDXComponents} */
|
||||
export function useMDXComponents() {
|
||||
return {
|
||||
Planet() {
|
||||
return 'Pluto'
|
||||
},
|
||||
h1(props) {
|
||||
return <h2 {...props} />
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And now passing a file path or URL to that file as `providerImportSource`,
|
||||
such as with `import.meta.resolve('./mdx-components.js')`:
|
||||
|
||||
```diff
|
||||
@@ -1,5 +1,5 @@
|
||||
import {jsx as _jsx, jsxs as _jsxs} from 'react/jsx-runtime'
|
||||
-import {useMDXComponents as _provideComponents} from 'xxx'
|
||||
+import {useMDXComponents as _provideComponents} from 'file:///Users/tilde/…/mdx-components.js'
|
||||
```
|
||||
|
||||
Now our locally defined components will be used in all MDX files!
|
||||
|
||||
[next-mdx-components]: https://nextjs.org/docs/pages/building-your-application/configuring/mdx
|
Loading…
Reference in New Issue
Block a user