Skip to content

Commit

Permalink
feat: replace xdm with MDX v2 (#152)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: We now use `@mdx-js/esbuild` instead of `xdm` and `xdmOptions` has been renamed to `mdxOptions`

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
  • Loading branch information
silvenon and kentcdodds committed Apr 1, 2022
1 parent 61c1a34 commit 8a4e6a6
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 49 deletions.
41 changes: 14 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ get a bundled version of these files to eval in the browser.
## This solution

This is an async function that will compile and bundle your MDX files and their
dependencies. It uses [esbuild](https://esbuild.github.io/), so it's VERY fast
and supports TypeScript files (for the dependencies of your MDX files). It also
uses [xdm](https://github.com/wooorm/xdm) which is a more modern and powerful
MDX compiler with fewer bugs and more features (and no extra runtime
requirements).
dependencies. It uses [MDX v2](https://mdxjs.com/blog/v2/) and
[esbuild](https://esbuild.github.io/), so it's VERY fast and supports TypeScript
files (for the dependencies of your MDX files).

Your source files could be local, in a remote github repo, in a CMS, or wherever
else and it doesn't matter. All `mdx-bundler` cares about is that you pass it
Expand Down Expand Up @@ -154,17 +152,6 @@ Why not?

</details>

<details>
<summary>
<strong>
"Why does this use XDM instead of @mdx-js?"
</strong>
</summary>

It has more features, fewer bugs, and no runtime!

</details>

<details>
<summary>
<strong>
Expand Down Expand Up @@ -321,18 +308,18 @@ file source code. You could get these from the filesystem or from a remote
database. If your MDX doesn't reference other files (or only imports things from
`node_modules`), then you can omit this entirely.

#### xdmOptions
#### mdxOptions

This allows you to modify the built-in xdm configuration (passed to the xdm
esbuild plugin). This can be helpful for specifying your own
This allows you to modify the built-in MDX configuration (passed to
`@mdx-js/esbuild`). This can be helpful for specifying your own
remarkPlugins/rehypePlugins.

The function is passed the default xdmOptions and the frontmatter.
The function is passed the default mdxOptions and the frontmatter.

```ts
bundleMDX({
source: mdxSource,
xdmOptions(options, frontmatter) {
mdxOptions(options, frontmatter) {
// this is the recommended way to add custom remark/rehype plugins:
// The syntax might look weird, but it protects you in case we add/remove
// plugins in the future.
Expand Down Expand Up @@ -505,7 +492,7 @@ the directory. If one option is set the other must be aswell.
_The Javascript bundle is not written to this directory and is still returned as
a string from `bundleMDX`._

This feature is best used with tweaks to `xdmOptions` and `esbuildOptions`. In
This feature is best used with tweaks to `mdxOptions` and `esbuildOptions`. In
the example below and `.png` files are written to the disk and then served from
`/file/`.

Expand All @@ -521,7 +508,7 @@ const {code} = await bundleMDX({
cwd: '/path/to/site/content',
bundleDirectory: '/path/to/site/public/file,
bundlePath: '/file/',
xdmOptions: options => {
mdxOptions: options => {
options.remarkPlugins = [remarkMdxImages]

return options
Expand Down Expand Up @@ -553,7 +540,7 @@ const {code} = await bundleMDX({
`bundleMDX` has a single type parameter which is the type of your frontmatter.
It defaults to `{[key: string]: any}` and must be an object. This is then used
to type the returned `frontmatter` and the frontmatter passed to
`esbuildOptions` and `xdmOptions`.
`esbuildOptions` and `mdxOptions`.

```ts
const {frontmatter} = bundleMDX<{title: string}>({source})
Expand All @@ -564,7 +551,7 @@ frontmatter.title // has type string
### Component Substitution

MDX Bundler passes on
[XDM's ability to substitute components](https://github.com/wooorm/xdm#mdx-content)
[MDX's ability to substitute components](https://mdxjs.com/docs/using-mdx/#components)
through the `components` prop on the component returned by `getMDXComponent`.

Here's an example that removes _p_ tags from around images.
Expand Down Expand Up @@ -653,7 +640,7 @@ import {remarkMdxImages} from 'remark-mdx-images'
const {code} = await bundleMDX({
source: mdxSource,
cwd: '/users/you/site/_content/pages',
xdmOptions: options => {
mdxOptions: options => {
options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkMdxImages]

return options
Expand Down Expand Up @@ -684,7 +671,7 @@ folder to be used in image sources.
const {code} = await bundleMDX({
source: mdxSource,
cwd: '/users/you/site/_content/pages',
xdmOptions: options => {
mdxOptions: options => {
options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkMdxImages]

return options
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
"mdx",
"bundler",
"mdx-bundler",
"esbuild",
"xdm"
"esbuild"
],
"author": "Kent C. Dodds <me@kentcdodds.com> (https://kentcdodds.com)",
"license": "MIT",
Expand Down Expand Up @@ -43,11 +42,11 @@
"@babel/runtime": "^7.16.3",
"@esbuild-plugins/node-resolve": "^0.1.4",
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
"@mdx-js/esbuild": "^2.0.0",
"gray-matter": "^4.0.3",
"remark-frontmatter": "^4.0.1",
"remark-mdx-frontmatter": "^1.1.1",
"uuid": "^8.3.2",
"xdm": "^3.3.0"
"uuid": "^8.3.2"
},
"peerDependencies": {
"esbuild": "0.11.x || 0.12.x || 0.13.x || 0.14.x"
Expand Down
10 changes: 5 additions & 5 deletions src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ import Demo from './demo'
import * as React from 'react'
import {left} from './left'
const Demo: React.FC = () => {
const Demo: React.FC = () => {
return <p>{left("TypeScript")}</p>
}
Expand Down Expand Up @@ -273,7 +273,7 @@ import {Demo} from './demo'
'./demo.ts': `
import React from 'react'
export const Demo: React.FC = () => {
export const Demo: React.FC = () => {
return <p>Sample</p>
}
`.trim(),
Expand Down Expand Up @@ -313,7 +313,7 @@ import {Sample} from './sample-component'
const {code} = await bundleMDX({
source: mdxSource,
cwd: path.join(process.cwd(), 'other'),
xdmOptions: options => {
mdxOptions: options => {
options.remarkPlugins = [remarkMdxImages]

return options
Expand Down Expand Up @@ -354,7 +354,7 @@ test('should output assets', async () => {
cwd: path.join(process.cwd(), 'other'),
bundleDirectory: path.join(process.cwd(), 'output'),
bundlePath: '/img/',
xdmOptions: options => {
mdxOptions: options => {
options.remarkPlugins = [remarkMdxImages]

return options
Expand All @@ -379,7 +379,7 @@ test('should output assets', async () => {
await bundleMDX({
source: mdxSource,
cwd: path.join(process.cwd(), 'other'),
xdmOptions: options => {
mdxOptions: options => {
options.remarkPlugins = [remarkMdxImages]

return options
Expand Down
12 changes: 6 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ async function bundleMDX({
file,
source,
files = {},
xdmOptions = options => options,
mdxOptions = options => options,
esbuildOptions = options => options,
globals = {},
cwd = path.join(process.cwd(), `__mdx_bundler_fake_dir__`),
Expand All @@ -36,10 +36,10 @@ async function bundleMDX({
}
/* c8 ignore stop */

// xdm is a native ESM, and we're running in a CJS context. This is the
// @mdx-js/esbuild is a native ESM, and we're running in a CJS context. This is the
// only way to import ESM within CJS
const [{default: xdmESBuild}, {default: remarkFrontmatter}] =
await Promise.all([import('xdm/esbuild.js'), import('remark-frontmatter')])
const [{default: mdxESBuild}, {default: remarkFrontmatter}] =
await Promise.all([import('@mdx-js/esbuild'), import('remark-frontmatter')])

let /** @type string */ code,
/** @type string */ entryPath,
Expand Down Expand Up @@ -184,8 +184,8 @@ async function bundleMDX({
resolveOptions: {basedir: cwd},
}),
inMemoryPlugin,
xdmESBuild(
xdmOptions(
mdxESBuild(
mdxOptions(
{
remarkPlugins: [
remarkFrontmatter,
Expand Down
14 changes: 7 additions & 7 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import type {Plugin, BuildOptions, Loader} from 'esbuild'
import type {ModuleInfo} from '@fal-works/esbuild-plugin-global-externals'
import type {CoreProcessorOptions} from 'xdm/lib/compile'
import type {ProcessorOptions} from '@mdx-js/esbuild/lib'
import type {GrayMatterOption, Input, GrayMatterFile} from 'gray-matter'

type ESBuildOptions = BuildOptions
Expand Down Expand Up @@ -57,18 +57,18 @@ type BundleMDXOptions<Frontmatter> = {
*/
files?: Record<string, string>
/**
* This allows you to modify the built-in xdm configuration (passed to xdm.compile).
* This allows you to modify the built-in MDX configuration (passed to @mdx-js/mdx compile).
* This can be helpful for specifying your own remarkPlugins/rehypePlugins.
*
* @param vfileCompatible the path and contents of the mdx file being compiled
* @param options the default options which you are expected to modify and return
* @returns the options to be passed to xdm.compile
* @returns the options to be passed to @mdx-js/mdx compile
*
* @example
* ```
* bundleMDX({
* source: mdxString,
* xdmOptions(options) {
* mdxOptions(options) {
* // this is the recommended way to add custom remark/rehype plugins:
* // The syntax might look weird, but it protects you in case we add/remove
* // plugins in the future.
Expand All @@ -80,10 +80,10 @@ type BundleMDXOptions<Frontmatter> = {
* })
* ```
*/
xdmOptions?: (
options: CoreProcessorOptions,
mdxOptions?: (
options: ProcessorOptions,
frontmatter: Frontmatter,
) => CoreProcessorOptions
) => ProcessorOptions
/**
* This allows you to modify the built-in esbuild configuration. This can be
* especially helpful for specifying the compilation target.
Expand Down

0 comments on commit 8a4e6a6

Please sign in to comment.