From 97b9d590e4ba11caf1e83cc9d7fc6a209739e0b2 Mon Sep 17 00:00:00 2001 From: Titus Date: Thu, 9 Feb 2023 19:22:09 +0100 Subject: [PATCH] Refactor to improve docs * Update dates * Update a bunch of examples * Refactor some wording * Update examples around `development` for `evaluate` Closes GH-2204. Closes GH-2254. --- docs/community/sponsor.server.mdx | 2 +- docs/community/support.server.mdx | 2 +- docs/docs/extending-mdx.server.mdx | 2 +- docs/docs/getting-started.server.mdx | 63 +++++++------- docs/docs/troubleshooting-mdx.server.mdx | 2 +- docs/docs/using-mdx.server.mdx | 26 +++--- docs/docs/what-is-mdx.server.mdx | 2 +- docs/guides/frontmatter.server.mdx | 2 +- docs/guides/gfm.server.mdx | 2 +- docs/guides/math.server.mdx | 2 +- docs/guides/mdx-on-demand.server.mdx | 26 ++++-- docs/guides/syntax-highlighting.server.mdx | 2 +- docs/migrating/v1.server.mdx | 2 +- docs/migrating/v2.server.mdx | 2 +- packages/mdx/readme.md | 96 +++++++++++++--------- 15 files changed, 138 insertions(+), 95 deletions(-) diff --git a/docs/community/sponsor.server.mdx b/docs/community/sponsor.server.mdx index 78e3fefb8..643c592b5 100644 --- a/docs/community/sponsor.server.mdx +++ b/docs/community/sponsor.server.mdx @@ -4,7 +4,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-06'), - modified: new Date('2022-01-25') + modified: new Date('2022-02-01') } # Sponsor diff --git a/docs/community/support.server.mdx b/docs/community/support.server.mdx index 4cce1e2bb..ba4c9b814 100644 --- a/docs/community/support.server.mdx +++ b/docs/community/support.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2019-07-03'), - modified: new Date('2022-01-25') + modified: new Date('2022-02-01') } # Support diff --git a/docs/docs/extending-mdx.server.mdx b/docs/docs/extending-mdx.server.mdx index f53b664d3..9a0394d9b 100644 --- a/docs/docs/extending-mdx.server.mdx +++ b/docs/docs/extending-mdx.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-06'), - modified: new Date('2023-01-18') + modified: new Date('2023-01-19') } # Extending MDX diff --git a/docs/docs/getting-started.server.mdx b/docs/docs/getting-started.server.mdx index e2e22a3c3..1d7fc273d 100644 --- a/docs/docs/getting-started.server.mdx +++ b/docs/docs/getting-started.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-05'), - modified: new Date('2022-06-17') + modified: new Date('2022-12-14') } # Getting started @@ -193,7 +193,7 @@ You can also import several types about the API of MDX files from `@types/mdx`. For example: ```js path="example.ts" -import type {MDXComponents} from 'mdx/types' +import type {MDXComponents} from 'mdx/types.js' ``` ### Security @@ -514,33 +514,42 @@ Which in turn lets us choose whether to use the `@mdx-js/mdx` or #### Astro -[Astro](https://astro.build/) has an [official MDX integration](https://docs.astro.build/guides/integrations-guide/mdx/). +[Astro](https://astro.build/) has their own MDX integration. You can add the integration with the Astro CLI (recommended): ```sh npx astro add mdx ``` -This base setup allows you to import markdown, Astro components, -and other MDX files as components. To use -other UI framework components in your MDX files -(e.g. Preact, Vue, Svelte and more), -see Astro’s [Framework components](https://docs.astro.build/en/core-concepts/framework-components/) guide. +This base setup allows you to import markdown, Astro components, and other MDX +files as components. +To use components from frameworks in your MDX files, see Astro’s +[Framework components](https://docs.astro.build/core-concepts/framework-components/) +guide. -To learn how to configure layouts, YAML frontmatter, and set up Astro’s -syntax highlighting, [see their MDX +For more on how to combine Astro and MDX, see [their MDX integration docs](https://docs.astro.build/guides/integrations-guide/mdx/). #### Create React App (CRA) - **Note**: rewiring with CRACO (see below) is currently required for CRA 5, - due to a bug in `react-scripts` + **Note**: it’s currently probably not a good idea to use CRA. + + + + **Note**: rewiring with CRACO is currently required for CRA 5, due to a bug + in `react-scripts` ([`facebook/create-react-app#12166`](https://github.com/facebook/create-react-app/issues/12166)), which is also tracked at [`mdx-js/mdx#1870`](https://github.com/mdx-js/mdx/discussions/1870). + + **Note**: warnings about CRACO having + `incorrect peer dependency "react-scripts@^4.0.0"` + can currently be ignored. + +
Expand example @@ -560,11 +569,6 @@ integration docs](https://docs.astro.build/guides/integrations-guide/mdx/). ```
-[CRA](https://github.com/facebook/create-react-app) supports webpack loaders -through webpack loader syntax in imports. - -Install the webpack loader [`@mdx-js/loader`][mdx-loader]. -
Expand CRACO example @@ -593,16 +597,15 @@ Install the webpack loader [`@mdx-js/loader`][mdx-loader]. ```
+[CRA](https://github.com/facebook/create-react-app) supports webpack loaders +through webpack loader syntax in imports. + +Install the webpack loader [`@mdx-js/loader`][mdx-loader]. + For importing MDX without the `!@mdx-js/loader!` prefix, you can add the loader to the webpack config, by rewiring `react-scripts` using [CRACO](http://github.com/gsoft-inc/craco). - - **Note**: warnings about CRACO having - `incorrect peer dependency "react-scripts@^4.0.0"` - can be ignored for the above to work. - - See also [¶ Webpack][webpack], which is used in CRA, and see [¶ React][react], which you’re likely using, for more info. @@ -624,15 +627,15 @@ on how to use MDX with Gatsby. Expand example ```js path="next.config.js" - import nextMDX from '@next/mdx' + import nextMdx from '@next/mdx' - const withMDX = nextMDX({ + const withMdx = nextMdx({ // By default only the .mdx extension is supported. extension: /\.mdx?$/, options: {/* providerImportSource: …, otherOptions… */} }) - export default withMDX({ + export default withMdx({ // Support MDX files as pages: pageExtensions: ['md', 'mdx', 'tsx', 'ts', 'jsx', 'js'], }) @@ -649,18 +652,18 @@ In order to use it, you need to configure the `providerImportSource` as well.
- Expand example + Expand provider example ```js path="next.config.js" - import nextMDX from '@next/mdx' + import nextMdx from '@next/mdx' - const withMDX = nextMDX({ + const withMdx = nextMdx({ // By default only the .mdx extension is supported. extension: /\.mdx?$/, options: {providerImportSource: '@mdx-js/react', /* otherOptions… */} }) - export default withMDX({ + export default withMdx({ // Support MDX files as pages: pageExtensions: ['md', 'mdx', 'tsx', 'ts', 'jsx', 'js'], }) diff --git a/docs/docs/troubleshooting-mdx.server.mdx b/docs/docs/troubleshooting-mdx.server.mdx index 7c5c0803b..68dd4e3da 100644 --- a/docs/docs/troubleshooting-mdx.server.mdx +++ b/docs/docs/troubleshooting-mdx.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-18'), - modified: new Date('2021-11-01') + modified: new Date('2022-02-01') } {/* lint disable maximum-heading-length */} diff --git a/docs/docs/using-mdx.server.mdx b/docs/docs/using-mdx.server.mdx index 5deb563cf..2488dd6e7 100644 --- a/docs/docs/using-mdx.server.mdx +++ b/docs/docs/using-mdx.server.mdx @@ -112,7 +112,8 @@ import React from 'react' import ReactDom from 'react-dom' import Example from './example.mdx' // Assumes an integration is used to compile MDX -> JS. -ReactDom.render(, document.querySelector('#root')) +const root = ReactDom.createRoot(document.getElementById('root')) +root.render() ``` The main content is exported as the default export. @@ -290,7 +291,9 @@ precedence). ## MDX provider +You probably don’t need a provider. Passing components is typically fine. +Providers often only add extra weight. Take for example this file: ```mdx path="post.mdx" @@ -311,12 +314,12 @@ const components = { table: Table } -ReactDom.render( - , - document.querySelector('#root') -) +const root = ReactDom.createRoot(document.getElementById('root')) +root.render() ``` +That works, those components are used. + But when you’re nesting MDX files (importing them into each other) it can become cumbersome. Like so: @@ -363,13 +366,13 @@ Set it up like so: table: Table } - ReactDom.render( -- , + const root = ReactDom.createRoot(document.getElementById('root')) +-root.render() ++root.render( + + -+ , - document.querySelector('#root') - ) ++ ++) ``` Now you can remove the explicit and verbose component passing: @@ -423,6 +426,9 @@ In this example the current context components are discarded: …which results in `h2`s using `Component3` and `h3`s using `Component4`. No component is used for `h1`. +If you’re not nesting MDX files, or not nesting them often, don’t use +providers: pass components explicitly. + [context]: https://reactjs.org/docs/context.html [start]: /docs/getting-started/ diff --git a/docs/docs/what-is-mdx.server.mdx b/docs/docs/what-is-mdx.server.mdx index a5e0f76aa..c17f46555 100644 --- a/docs/docs/what-is-mdx.server.mdx +++ b/docs/docs/what-is-mdx.server.mdx @@ -6,7 +6,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2018-08-11'), - modified: new Date('2021-11-01') + modified: new Date('2023-01-06') } # What is MDX? diff --git a/docs/guides/frontmatter.server.mdx b/docs/guides/frontmatter.server.mdx index 6c7acb593..6cfb34e75 100644 --- a/docs/guides/frontmatter.server.mdx +++ b/docs/guides/frontmatter.server.mdx @@ -4,7 +4,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-06'), - modified: new Date('2022-06-17') + modified: new Date('2022-12-14') } # Frontmatter diff --git a/docs/guides/gfm.server.mdx b/docs/guides/gfm.server.mdx index 1efa6df09..ab169c0cb 100644 --- a/docs/guides/gfm.server.mdx +++ b/docs/guides/gfm.server.mdx @@ -4,7 +4,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-06'), - modified: new Date('2022-06-17') + modified: new Date('2022-12-14') } # GitHub flavored markdown (GFM) diff --git a/docs/guides/math.server.mdx b/docs/guides/math.server.mdx index 440389582..df827db89 100644 --- a/docs/guides/math.server.mdx +++ b/docs/guides/math.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-06'), - modified: new Date('2022-06-17') + modified: new Date('2022-12-14') } # Math diff --git a/docs/guides/mdx-on-demand.server.mdx b/docs/guides/mdx-on-demand.server.mdx index 8749a2ad4..57e2be2b5 100644 --- a/docs/guides/mdx-on-demand.server.mdx +++ b/docs/guides/mdx-on-demand.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-11-13'), - modified: new Date('2021-11-13') + modified: new Date('2021-11-14') } # MDX on demand @@ -28,7 +28,14 @@ On the server: ```js path="server.js" import {compile} from '@mdx-js/mdx' -const code = String(await compile('# hi', {outputFormat: 'function-body' /* …otherOptions */ })) +const code = String(await compile('# hi', { + outputFormat: 'function-body', + development: false + // ^-- Generate code for production. + // `false` if you use `/jsx-runtime` on client, `true` if you use + // `/jsx-dev-runtime`. + /* …otherOptions */ +})) // To do: send `code` to the client somehow. ``` @@ -36,7 +43,8 @@ On the client: ```js path="client.js" import {run} from '@mdx-js/mdx' -import * as runtime from 'react/jsx-runtime' +import * as runtime from 'react/jsx-runtime' // Production. +// import * as runtime from 'react/jsx-dev-runtime' // Development. const code = '' // To do: get `code` from server somehow. @@ -64,7 +72,8 @@ Next. ```js path="pages/hello.js" import {useState, useEffect, Fragment} from 'react' -import * as runtime from 'react/jsx-runtime' +import * as runtime from 'react/jsx-runtime' // Production. +// import * as runtime from 'react/jsx-dev-runtime' // Development. import {compile, run} from '@mdx-js/mdx' export default function Page({code}) { @@ -82,7 +91,14 @@ export default function Page({code}) { export async function getStaticProps() { const code = String( - await compile('# hi', {outputFormat: 'function-body' /* …otherOptions */}) + await compile('# hi', { + outputFormat: 'function-body', + development: false, + // ^-- Generate code for production. + // `false` if you use `/jsx-runtime` on client, `true` if you use + // `/jsx-dev-runtime`. + /* …otherOptions */ + }) ) return {props: {code}} } diff --git a/docs/guides/syntax-highlighting.server.mdx b/docs/guides/syntax-highlighting.server.mdx index 7e13f3189..cc774d008 100644 --- a/docs/guides/syntax-highlighting.server.mdx +++ b/docs/guides/syntax-highlighting.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'Titus Wormer', github: 'wooorm', twitter: 'wooorm'} ], published: new Date('2021-10-06'), - modified: new Date('2022-06-17') + modified: new Date('2022-08-27') } # Syntax highlighting diff --git a/docs/migrating/v1.server.mdx b/docs/migrating/v1.server.mdx index 37edac30d..95cdbcbf0 100644 --- a/docs/migrating/v1.server.mdx +++ b/docs/migrating/v1.server.mdx @@ -5,7 +5,7 @@ export const info = { {name: 'John Otander', github: 'johno', twitter: '4lpine'} ], published: new Date('2019-04-04'), - modified: new Date('2021-11-01') + modified: new Date('2021-10-17') } diff --git a/docs/migrating/v2.server.mdx b/docs/migrating/v2.server.mdx index 87f262a82..29cf70319 100644 --- a/docs/migrating/v2.server.mdx +++ b/docs/migrating/v2.server.mdx @@ -387,7 +387,7 @@ You can update your code as follows: const components = {/* … */} const value = '# hi' - const {default: Content} = await evaluate(value, {...provider, ...runtime}) + const {default: Content} = await evaluate(value, {...provider, ...runtime, development: false}) export default () => ( diff --git a/packages/mdx/readme.md b/packages/mdx/readme.md index 9ef3b7819..23d98d4be 100644 --- a/packages/mdx/readme.md +++ b/packages/mdx/readme.md @@ -130,7 +130,7 @@ MDX document to parse (`string`, [`Buffer`][buffer] in UTF-8, [`vfile`][vfile], or anything that can be given to `vfile`).
-Example +Expand example ```js import {VFile} from 'vfile' @@ -149,7 +149,7 @@ await compile(new VFile({path: 'path/to/file.mdx', value: '🤭'})) List of [remark plugins][remark-plugins], presets, and pairs.
-Example +Expand example ```js import remarkFrontmatter from 'remark-frontmatter' // YAML and such. @@ -168,7 +168,7 @@ await compile(file, {remarkPlugins: [[remarkGfm, {singleTilde: false}], remarkFr List of [rehype plugins][rehype-plugins], presets, and pairs.
-Example +Expand example ```js import rehypeKatex from 'rehype-katex' // Render math with KaTeX. @@ -200,7 +200,7 @@ In particular, you might want to pass `clobberPrefix`, `footnoteLabel`, and `footnoteBackLabel`.
-Example +Expand example ```js compile({value: '…'}, {remarkRehypeOptions: {clobberPrefix: 'comment-1'}}) @@ -233,7 +233,7 @@ The format cannot be detected if a file is passed without a path or extension: So pass a full vfile (with `path`) or an object with a path.
-Example +Expand example ```js compile({value: '…'}) // Seen as MDX @@ -256,7 +256,7 @@ because in those it affects *which* files are “registered”: ###### `options.outputFormat` -Output format to generate (`'program' | 'function-body'`, default: `'program'`). +Output format to generate (`'function-body' | 'program'`, default: `'program'`). In most cases `'program'` should be used, as it results in a whole program. Internally, [`evaluate`][eval] uses `outputFormat: 'function-body'` to compile to code that can be `eval`ed with [`run`][run]. @@ -275,7 +275,7 @@ statements, but you can support them by setting [`options.useDynamicImport`][usedynamicimport].
-Example +Expand example A module `example.js`: @@ -322,7 +322,7 @@ JavaScript modules, whereas `import()` is available inside function bodies. When you turn `useDynamicImport` on, you should probably set [`options.baseUrl`][baseurl] too.
-Example +Expand example Say we have a couple modules: @@ -371,7 +371,7 @@ imports should run relative the path *b*. Another example is when evaluating code, whether in Node or a browser.
-Example +Expand example Say we have a module `example.js`: @@ -406,7 +406,7 @@ The default can be set to `true` in Node.js through environment variables: set `NODE_ENV=development`.
-Example +Expand example Say we had some MDX that references a component that can be passed or provided at runtime: @@ -476,7 +476,7 @@ When given, the resulting file will have a `map` field set to a source map (in object form).
-Example +Expand example Assuming `example.mdx` from [§ Use][use] exists, then: @@ -515,7 +515,7 @@ The provider must export a `useMDXComponents`, which is called to access an object of components.
-Example +Expand example If `file` is the contents of `example.mdx` from [§ Use][use], then: @@ -556,7 +556,7 @@ The default is to compile JSX away so that the resulting file is immediately runnable.
-Example +Expand example If `file` is the contents of `example.mdx` from [§ Use][use], then: @@ -598,7 +598,7 @@ The classic runtime compiles to calls such as `h('p')`, the automatic runtime compiles to `import _jsx from '$importSource/jsx-runtime'\n_jsx('p')`.
-Example +Expand example If `file` is the contents of `example.mdx` from [§ Use][use], then: @@ -625,10 +625,10 @@ compile(file, {jsxRuntime: 'classic'}) Place to import automatic JSX runtimes from (`string?`, default: `'react'`). When in the `automatic` runtime, this is used to define an import for -`_Fragment`, `_jsx`, and `_jsxs`. +`Fragment`, `jsx`, `jsxs`, and `jsxDEV`.
-Example +Expand example If `file` is the contents of `example.mdx` from [§ Use][use], then: @@ -657,7 +657,7 @@ You should most probably define `pragmaFrag` and `pragmaImportSource` too when changing this.
-Example +Expand example If `file` is the contents of `example.mdx` from [§ Use][use], then: @@ -707,7 +707,7 @@ See `options.pragma` for an example. `Promise` — Promise that resolves to the compiled JS as a [vfile][].
-Example +Expand example ```js import remarkPresetLintConsistent from 'remark-preset-lint-consistent' // Lint rules to check for consistent markdown. @@ -749,6 +749,8 @@ Typically, `import` (or `export … from`) do not work here. They can be compiled to dynamic `import()` by passing [`options.useDynamicImport`][usedynamicimport]. +> ☢️ **Danger**: you likely must set `development: boolean`. + ###### `file` See [`compile`][compile]. @@ -759,25 +761,33 @@ Most options are the same as [`compile`][compile], with the following exceptions: * `providerImportSource` is replaced by `useMDXComponents` -* `jsx*` and `pragma*` options are replaced by `jsx`, `jsxs`, and `Fragment` +* `jsx*` and `pragma*` options are replaced by `Fragment`, `jsx`, `jsxs`, and + `jsxDEV` * `outputFormat` is set to `function-body` ###### `options.jsx` ###### `options.jsxs` +###### `options.jsxDEV` + ###### `options.Fragment` -These three options are required. +These options are required: `Fragment` always, when `development: true` +then `jsx` and `jsxs`, when `development: false` then `jsxDEV`. They come from an automatic JSX runtime that you must import yourself.
-Example +Expand example ```js import * as runtime from 'react/jsx-runtime' -const {default: Content} = await evaluate('# hi', {...runtime, ...otherOptions}) +const {default: Content} = await evaluate('# hi', { + ...runtime, + ...otherOptions, + development: false +}) ```
@@ -787,25 +797,30 @@ const {default: Content} = await evaluate('# hi', {...runtime, ...otherOptions}) Needed if you want to support a provider.
-Example +Expand example ```js import * as provider from '@mdx-js/react' import * as runtime from 'react/jsx-runtime' -const {default: Content} = await evaluate('# hi', {...provider, ...runtime, ...otherOptions}) +const {default: Content} = await evaluate('# hi', { + ...provider, + ...runtime, + ...otherOptions, + development: false +}) ```
###### Returns -`Promise` — Promise that resolves to something that looks a bit like +`Promise` — Promise that resolves to something that looks a bit like a module: an object with a `default` field set to the component and anything else that was exported from the MDX file available too.
-Example +Expand example Assuming the contents of `example.mdx` from [§ Use][use] was in `file`, then: @@ -813,7 +828,7 @@ Assuming the contents of `example.mdx` from [§ Use][use] was in `file`, then: import * as runtime from 'react/jsx-runtime' import {evaluate} from '@mdx-js/mdx' -console.log(await evaluate(file, {...runtime})) +console.log(await evaluate(file, {...runtime, development: false})) ``` …yields: @@ -856,8 +871,8 @@ Run MDX compiled as [`options.outputFormat: 'function-body'`][outputformat]. ###### `options` -You can pass `jsx`, `jsxs`, and `Fragment` from an automatic JSX runtime as -`options`. +You can pass `Fragment`, `jsx`, `jsxs`, and `jsxDEV`, from an automatic JSX +runtime as `options`. You can also pass `useMDXComponents` from a provider in options if the MDX is compiled with `options.providerImportSource: '#'` (the exact value of this compile option doesn’t matter). @@ -868,14 +883,17 @@ All other options have to be passed to `compile` instead. `Promise` — See `evaluate`
-Example +Expand example On the server: ```js import {compile} from '@mdx-js/mdx' -const code = String(await compile('# hi', {outputFormat: 'function-body'})) +const code = String(await compile('# hi', { + outputFormat: 'function-body', + development: false +})) // To do: send `code` to the client somehow. ``` @@ -934,15 +952,15 @@ what unified does: please read through the [`unifiedjs/unified`][unified] readme know about unified: [`core.js#L65`][core]. The processor goes through these steps: -1. Parse MDX (serialized markdown with embedded JSX, ESM, and expressions) +1. parse MDX (serialized markdown with embedded JSX, ESM, and expressions) to mdast (markdown syntax tree) -2. Transform through remark (markdown ecosystem) -3. Transform mdast to hast (HTML syntax tree) -4. Transform through rehype (HTML ecosystem) -5. Transform hast to esast (JS syntax tree) -6. Do the work needed to get a component -7. Transform through recma (JS ecosystem) -8. Serialize esast as JavaScript +2. transform through remark (markdown ecosystem) +3. transform mdast to hast (HTML syntax tree) +4. transform through rehype (HTML ecosystem) +5. transform hast to esast (JS syntax tree) +6. do the work needed to get a component +7. transform through recma (JS ecosystem) +8. serialize esast as JavaScript The *input* is MDX (serialized markdown with embedded JSX, ESM, and expressions).