Skip to content

Commit 6a8b3a7

Browse files
authored
feat: merge bundleMDX and bundleMDXFile (#125)
BREAKING CHANGE: The first argument to `bundleMDX` has been removed in favor of a `source` option.
1 parent aedd586 commit 6a8b3a7

File tree

5 files changed

+366
-244
lines changed

5 files changed

+366
-244
lines changed

README.md

Lines changed: 108 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,13 @@ the esbuild version mdx-bundler uses.
187187
- [Installation](#installation)
188188
- [Usage](#usage)
189189
- [Options](#options)
190+
- [Returns](#returns)
191+
- [Types](#types)
190192
- [Component Substitution](#component-substitution)
191193
- [Frontmatter and const](#frontmatter-and-const)
192194
- [Accessing named exports](#accessing-named-exports)
193195
- [Image Bundling](#image-bundling)
194-
- [bundleMDXFile](#bundlemdxfile)
196+
- [Bundling a file.](#bundling-a-file)
195197
- [Known Issues](#known-issues)
196198
- [Inspiration](#inspiration)
197199
- [Other Solutions](#other-solutions)
@@ -236,7 +238,8 @@ Here's a **neat** demo:
236238
<Demo />
237239
`.trim()
238240

239-
const result = await bundleMDX(mdxSource, {
241+
const result = await bundleMDX({
242+
source: mdxSource,
240243
files: {
241244
'./demo.tsx': `
242245
import * as React from 'react'
@@ -297,6 +300,19 @@ Ultimately, this gets rendered (basically):
297300

298301
### Options
299302

303+
#### source
304+
305+
The `string` source of your MDX.
306+
307+
_Can not be set if `file` is set_
308+
309+
#### file
310+
311+
The path to the file on your disk with the MDX in. You will probabbly want to
312+
set [cwd](#cwd) as well.
313+
314+
_Can not be set if `source` is set_
315+
300316
#### files
301317

302318
The `files` config is an object of all the files you're bundling. The key is the
@@ -311,9 +327,12 @@ This allows you to modify the built-in xdm configuration (passed to the xdm
311327
esbuild plugin). This can be helpful for specifying your own
312328
remarkPlugins/rehypePlugins.
313329

330+
The function is passed the default xdmOptions and the frontmatter.
331+
314332
```ts
315-
bundleMDX(mdxString, {
316-
xdmOptions(options) {
333+
bundleMDX({
334+
source: mdxSource,
335+
xdmOptions(options, frontmatter) {
317336
// this is the recommended way to add custom remark/rehype plugins:
318337
// The syntax might look weird, but it protects you in case we add/remove
319338
// plugins in the future.
@@ -328,12 +347,13 @@ bundleMDX(mdxString, {
328347
#### esbuildOptions
329348

330349
You can customize any of esbuild options with the option `esbuildOptions`. This
331-
takes a function which is passed the default esbuild options and expects an
332-
options object to be returned.
350+
takes a function which is passed the default esbuild options and the frontmatter
351+
and expects an options object to be returned.
333352

334353
```typescript
335-
bundleMDX(mdxSource, {
336-
esbuildOptions(options) {
354+
bundleMDX({
355+
source: mdxSource,
356+
esbuildOptions(options, frontmatter) {
337357
options.minify = false
338358
options.target = [
339359
'es2020',
@@ -366,7 +386,8 @@ and once for this MDX component). This is wasteful and you'd be better off just
366386
telling esbuild to _not_ bundle `d3` and you can pass it to the component
367387
yourself when you call `getMDXComponent`.
368388

369-
Global external configuration options: https://www.npmjs.com/package/@fal-works/esbuild-plugin-global-externals
389+
Global external configuration options:
390+
https://www.npmjs.com/package/@fal-works/esbuild-plugin-global-externals
370391

371392
Here's an example:
372393

@@ -382,7 +403,8 @@ import leftPad from 'left-pad'
382403
<div>{leftPad("Neat demo!", 12, '!')}</div>
383404
`.trim()
384405

385-
const result = await bundleMDX(mdxSource, {
406+
const result = await bundleMDX({
407+
source: mdxSource,
386408
// NOTE: this is *only* necessary if you want to share deps between your MDX
387409
// file bundle and the host app. Otherwise, all deps will just be bundled.
388410
// So it'll work either way, this is just an optimization to avoid sending
@@ -449,7 +471,8 @@ Here's a **neat** demo:
449471
<Demo />
450472
`.trim()
451473

452-
const result = await bundleMDX(mdxSource, {
474+
const result = await bundleMDX({
475+
source: mdxSource,
453476
cwd: '/users/you/site/_content/pages',
454477
})
455478

@@ -465,7 +488,7 @@ Your function is passed the current gray-matter configuration for you to modify.
465488
Return your modified configuration object for gray matter.
466489

467490
```js
468-
bundleMDX(mdxString, {
491+
bundleMDX({
469492
grayMatterOptions: options => {
470493
options.excerpt = true
471494

@@ -474,6 +497,46 @@ bundleMDX(mdxString, {
474497
})
475498
```
476499

500+
#### bundleDirectory & bundlePath
501+
502+
This allows you to set the output directory for the bundle and the public URL to
503+
the directory. If one option is set the other must be aswell.
504+
505+
_The Javascript bundle is not written to this directory and is still returned as
506+
a string from `bundleMDX`._
507+
508+
This feature is best used with tweaks to `xdmOptions` and `esbuildOptions`. In
509+
the example below and `.png` files are written to the disk and then served from
510+
`/file/`.
511+
512+
This allows you to store assets with your MDX and then have esbuild process them
513+
like anything else.
514+
515+
_It is reccomended that each bundle has its own `bundleDirectory` so that
516+
multiple bundles don't overwrite each others assets._
517+
518+
```ts
519+
const {code} = await bundleMDX({
520+
file: '/path/to/site/content/file.mdx',
521+
cwd: '/path/to/site/content',
522+
bundleDirectory: '/path/to/site/public/file,
523+
bundlePath: '/file/',
524+
xdmOptions: options => {
525+
options.remarkPlugins = [remarkMdxImages]
526+
527+
return options
528+
},
529+
esbuildOptions: options => {
530+
options.loader = {
531+
...options.loader,
532+
'.png': 'file',
533+
}
534+
535+
return options
536+
},
537+
})
538+
```
539+
477540
### Returns
478541

479542
`bundleMDX` returns a promise for an object with the following properties.
@@ -483,6 +546,21 @@ bundleMDX(mdxString, {
483546
- `matter` - The whole
484547
[object returned by gray-matter](https://github.com/jonschlinkert/gray-matter#returned-object)
485548

549+
### Types
550+
551+
`mdx-bundler` supplies complete typings within its own package.
552+
553+
`bundleMDX` has a single type parameter which is the type of your frontmatter.
554+
It defaults to `{[key: string]: any}` and must be an object. This is then used
555+
to type the returned `frontmatter` and the frontmatter passed to
556+
`esbuildOptions` and `xdmOptions`.
557+
558+
```ts
559+
const {frontmatter} = bundleMDX<{title: string}>({source})
560+
561+
frontmatter.title // has type string
562+
```
563+
486564
### Component Substitution
487565

488566
MDX Bundler passes on
@@ -532,17 +610,16 @@ export const exampleImage = 'https://example.com/image.jpg'
532610

533611
### Accessing named exports
534612

535-
You can use `getMDXExport` instead of `getMDXComponent` to treat the mdx file as a module instead of just a component.
536-
It takes the same arguments that `getMDXComponent` does.
613+
You can use `getMDXExport` instead of `getMDXComponent` to treat the mdx file as
614+
a module instead of just a component. It takes the same arguments that
615+
`getMDXComponent` does.
537616

538617
```mdx
539618
---
540619
title: Example Post
541620
---
542621

543-
export const toc = [
544-
{ depth: 1, value: 'The title' }
545-
]
622+
export const toc = [{depth: 1, value: 'The title'}]
546623

547624
# The title
548625
```
@@ -560,6 +637,7 @@ function MDXPage({code}: {code: string}) {
560637
return <Component />
561638
}
562639
```
640+
563641
### Image Bundling
564642

565643
With the [cwd](#cwd) and the remark plugin
@@ -572,7 +650,8 @@ which outputs the images as inline data urls in the returned code.
572650
```js
573651
import {remarkMdxImages} from 'remark-mdx-images'
574652

575-
const {code} = await bundleMDX(mdxSource, {
653+
const {code} = await bundleMDX({
654+
source: mdxSource,
576655
cwd: '/users/you/site/_content/pages',
577656
xdmOptions: options => {
578657
options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkMdxImages]
@@ -602,7 +681,8 @@ folder to be used in image sources.
602681
```js
603682
// For the file `_content/pages/about.mdx`
604683

605-
const {code} = await bundleMDX(mdxSource, {
684+
const {code} = await bundleMDX({
685+
source: mdxSource,
606686
cwd: '/users/you/site/_content/pages',
607687
xdmOptions: options => {
608688
options.remarkPlugins = [...(options.remarkPlugins ?? []), remarkMdxImages]
@@ -628,24 +708,22 @@ const {code} = await bundleMDX(mdxSource, {
628708
})
629709
```
630710
631-
### bundleMDXFile
711+
### Bundling a file.
632712
633713
If your MDX file is on your disk you can save some time and code by having
634-
`esbuild` read the file for you. To do this mdx-bundler provides the function
635-
`bundleMDXFile` which works the same as `bundleMDX` except it's first option is
636-
the path to the mdx file instead of the mdx source.
714+
`mdx-bundler` read the file for you. Instead of supplying a `source` string you
715+
can set `file` to the path of the MDX on disk. Set `cwd` to it's folder so that
716+
relative imports work.
637717
638718
```js
639-
import {bundleMDXFile} from 'mdx-bundler'
719+
import {bundleMDX} from 'mdx-bundler'
640720

641-
const {code, frontmatter} = await bundleMDXFile(
642-
'/users/you/site/content/file.mdx',
643-
)
721+
const {code, frontmatter} = await bundleMDX({
722+
file: '/users/you/site/content/file.mdx',
723+
cwd: '/users/you/site/content/',
724+
})
644725
```
645726
646-
`cwd` will be automatically set to the `dirname` of the given file path, you can
647-
still override this. All other options work the same as they do for `bundleMDX`.
648-
649727
### Known Issues
650728
651729
#### Cloudflare Workers

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@
4040
"validate": "kcd-scripts validate"
4141
},
4242
"dependencies": {
43-
"@babel/runtime": "^7.15.4",
43+
"@babel/runtime": "^7.16.3",
4444
"@esbuild-plugins/node-resolve": "^0.1.4",
4545
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
4646
"gray-matter": "^4.0.3",
4747
"remark-frontmatter": "^4.0.1",
48-
"remark-mdx-frontmatter": "^1.0.1",
48+
"remark-mdx-frontmatter": "^1.1.1",
4949
"uuid": "^8.3.2",
50-
"xdm": "^3.2.0"
50+
"xdm": "^3.3.0"
5151
},
5252
"peerDependencies": {
5353
"esbuild": "0.11.x || 0.12.x || 0.13.x"
@@ -61,8 +61,8 @@
6161
"@types/uuid": "^8.3.1",
6262
"c8": "^7.10.0",
6363
"cross-env": "^7.0.3",
64-
"esbuild": "^0.13.12",
65-
"jsdom": "^18.0.1",
64+
"esbuild": "^0.13.13",
65+
"jsdom": "^18.1.0",
6666
"kcd-scripts": "^11.2.2",
6767
"left-pad": "^1.3.0",
6868
"mdx-test-data": "^1.0.1",

0 commit comments

Comments
 (0)