@astrojs/mdx 0.0.0-imgcache-20220929145446

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +209 -0
  3. package/LICENSE +61 -0
  4. package/README.md +527 -0
  5. package/dist/index.d.ts +15 -0
  6. package/dist/index.js +131 -0
  7. package/dist/plugins.d.ts +11 -0
  8. package/dist/plugins.js +214 -0
  9. package/dist/rehype-collect-headings.d.ts +6 -0
  10. package/dist/rehype-collect-headings.js +47 -0
  11. package/dist/remark-prism.d.ts +2 -0
  12. package/dist/remark-prism.js +17 -0
  13. package/dist/remark-shiki.d.ts +3 -0
  14. package/dist/remark-shiki.js +69 -0
  15. package/dist/utils.d.ts +18 -0
  16. package/dist/utils.js +74 -0
  17. package/package.json +71 -0
  18. package/src/index.ts +167 -0
  19. package/src/plugins.ts +273 -0
  20. package/src/rehype-collect-headings.ts +50 -0
  21. package/src/remark-prism.ts +18 -0
  22. package/src/remark-shiki.ts +95 -0
  23. package/src/utils.ts +97 -0
  24. package/test/fixtures/mdx-component/src/components/Test.mdx +3 -0
  25. package/test/fixtures/mdx-component/src/pages/glob.astro +11 -0
  26. package/test/fixtures/mdx-component/src/pages/index.astro +5 -0
  27. package/test/fixtures/mdx-escape/src/components/Em.astro +7 -0
  28. package/test/fixtures/mdx-escape/src/components/P.astro +1 -0
  29. package/test/fixtures/mdx-escape/src/components/Title.astro +1 -0
  30. package/test/fixtures/mdx-escape/src/pages/html-tag.mdx +5 -0
  31. package/test/fixtures/mdx-escape/src/pages/index.mdx +13 -0
  32. package/test/fixtures/mdx-frontmatter/src/layouts/Base.astro +38 -0
  33. package/test/fixtures/mdx-frontmatter/src/pages/glob.json.js +9 -0
  34. package/test/fixtures/mdx-frontmatter/src/pages/index.mdx +10 -0
  35. package/test/fixtures/mdx-frontmatter/src/pages/with-headings.mdx +7 -0
  36. package/test/fixtures/mdx-frontmatter-injection/astro.config.mjs +12 -0
  37. package/test/fixtures/mdx-frontmatter-injection/node_modules/.bin/astro +17 -0
  38. package/test/fixtures/mdx-frontmatter-injection/package.json +12 -0
  39. package/test/fixtures/mdx-frontmatter-injection/src/layouts/Base.astro +17 -0
  40. package/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs +20 -0
  41. package/test/fixtures/mdx-frontmatter-injection/src/pages/glob.json.js +6 -0
  42. package/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx +7 -0
  43. package/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx +23 -0
  44. package/test/fixtures/mdx-frontmatter-injection/src/pages/with-overrides.mdx +7 -0
  45. package/test/fixtures/mdx-get-headings/src/pages/pages.json.js +11 -0
  46. package/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx +8 -0
  47. package/test/fixtures/mdx-get-headings/src/pages/test.mdx +9 -0
  48. package/test/fixtures/mdx-get-static-paths/src/content/1.mdx +5 -0
  49. package/test/fixtures/mdx-get-static-paths/src/pages/[slug].astro +34 -0
  50. package/test/fixtures/mdx-namespace/astro.config.mjs +6 -0
  51. package/test/fixtures/mdx-namespace/node_modules/.bin/astro +17 -0
  52. package/test/fixtures/mdx-namespace/package.json +10 -0
  53. package/test/fixtures/mdx-namespace/src/components/Component.jsx +6 -0
  54. package/test/fixtures/mdx-namespace/src/pages/object.mdx +3 -0
  55. package/test/fixtures/mdx-namespace/src/pages/star.mdx +3 -0
  56. package/test/fixtures/mdx-page/astro.config.ts +5 -0
  57. package/test/fixtures/mdx-page/node_modules/.bin/astro +17 -0
  58. package/test/fixtures/mdx-page/package.json +9 -0
  59. package/test/fixtures/mdx-page/src/pages/index.mdx +3 -0
  60. package/test/fixtures/mdx-page/src/styles.css +3 -0
  61. package/test/fixtures/mdx-plugins/src/pages/with-plugins.mdx +19 -0
  62. package/test/fixtures/mdx-plus-react/astro.config.mjs +6 -0
  63. package/test/fixtures/mdx-plus-react/node_modules/.bin/astro +17 -0
  64. package/test/fixtures/mdx-plus-react/package.json +10 -0
  65. package/test/fixtures/mdx-plus-react/src/components/Component.jsx +5 -0
  66. package/test/fixtures/mdx-plus-react/src/pages/index.astro +11 -0
  67. package/test/fixtures/mdx-syntax-hightlighting/src/pages/index.mdx +9 -0
  68. package/test/fixtures/mdx-url-export/src/pages/pages.json.js +9 -0
  69. package/test/fixtures/mdx-url-export/src/pages/test-1.mdx +1 -0
  70. package/test/fixtures/mdx-url-export/src/pages/test-2.mdx +1 -0
  71. package/test/fixtures/mdx-url-export/src/pages/with-url-override.mdx +3 -0
  72. package/test/fixtures/mdx-vite-env-vars/astro.config.mjs +9 -0
  73. package/test/fixtures/mdx-vite-env-vars/node_modules/.bin/astro +17 -0
  74. package/test/fixtures/mdx-vite-env-vars/package.json +7 -0
  75. package/test/fixtures/mdx-vite-env-vars/src/pages/frontmatter.json.js +7 -0
  76. package/test/fixtures/mdx-vite-env-vars/src/pages/vite-env-vars.mdx +38 -0
  77. package/test/mdx-component.test.js +112 -0
  78. package/test/mdx-escape.test.js +32 -0
  79. package/test/mdx-frontmatter-injection.test.js +56 -0
  80. package/test/mdx-frontmatter.test.js +77 -0
  81. package/test/mdx-get-headings.test.js +60 -0
  82. package/test/mdx-get-static-paths.test.js +32 -0
  83. package/test/mdx-namespace.test.js +83 -0
  84. package/test/mdx-page.test.js +64 -0
  85. package/test/mdx-plugins.test.js +211 -0
  86. package/test/mdx-plus-react.test.js +25 -0
  87. package/test/mdx-syntax-highlighting.test.js +91 -0
  88. package/test/mdx-url-export.test.js +28 -0
  89. package/test/mdx-vite-env-vars.test.js +54 -0
  90. package/tsconfig.json +10 -0
package/README.md ADDED
@@ -0,0 +1,527 @@
1
+ # @astrojs/mdx 📝
2
+
3
+ This **[Astro integration][astro-integration]** enables the usage of [MDX](https://mdxjs.com/) components and allows you to create pages as `.mdx` files.
4
+
5
+ - <strong>[Why MDX?](#why-mdx)</strong>
6
+ - <strong>[Installation](#installation)</strong>
7
+ - <strong>[Usage](#usage)</strong>
8
+ - <strong>[Configuration](#configuration)</strong>
9
+ - <strong>[Examples](#examples)</strong>
10
+ - <strong>[Troubleshooting](#troubleshooting)</strong>
11
+ - <strong>[Contributing](#contributing)</strong>
12
+ - <strong>[Changelog](#changelog)</strong>
13
+
14
+ ## Why MDX?
15
+
16
+ MDX is the defacto solution for embedding components, such as interactive charts or alerts, within Markdown content. If you have existing content authored in MDX, this integration makes migrating to Astro a breeze.
17
+
18
+ **Want to learn more about MDX before using this integration?**
19
+ Check out [“What is MDX?”](https://mdxjs.com/docs/what-is-mdx/), a deep-dive on the MDX format.
20
+
21
+ ## Installation
22
+
23
+ ### Quick Install
24
+
25
+ The `astro add` command-line tool automates the installation for you. Run one of the following commands in a new terminal window. (If you aren't sure which package manager you're using, run the first command.) Then, follow the prompts, and type "y" in the terminal (meaning "yes") for each one.
26
+
27
+ ```sh
28
+ # Using NPM
29
+ npx astro add mdx
30
+ # Using Yarn
31
+ yarn astro add mdx
32
+ # Using PNPM
33
+ pnpm astro add mdx
34
+ ```
35
+
36
+ If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
37
+
38
+ ### Manual Install
39
+
40
+ First, install the `@astrojs/mdx` package using your package manager. If you're using npm or aren't sure, run this in the terminal:
41
+
42
+ ```sh
43
+ npm install @astrojs/mdx
44
+ ```
45
+
46
+ Then, apply this integration to your `astro.config.*` file using the `integrations` property:
47
+
48
+ __`astro.config.mjs`__
49
+
50
+ ```js
51
+ import { defineConfig } from 'astro/config';
52
+ import mdx from '@astrojs/mdx';
53
+
54
+ export default defineConfig({
55
+ // ...
56
+ integrations: [mdx()],
57
+ });
58
+ ```
59
+
60
+ Finally, restart the dev server.
61
+
62
+ ### Editor Integration
63
+
64
+ [VS Code](https://code.visualstudio.com/) supports Markdown by default. However, for MDX editor support, you may wish to add the following setting in your VSCode config. This ensures authoring MDX files provides a Markdown-like editor experience.
65
+
66
+ ```json title=".vscode/settings.json"
67
+ "files.associations": {
68
+ "*.mdx": "markdown"
69
+ }
70
+ ```
71
+
72
+ ## Usage
73
+
74
+ You can [add MDX pages to your project](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages) by adding `.mdx` files within your `src/pages/` directory.
75
+
76
+ ### Components
77
+
78
+ To use components in your MDX pages in Astro, head to our [UI framework documentation][astro-ui-frameworks]. You'll explore:
79
+ - 📦 how framework components are loaded,
80
+ - 💧 client-side hydration options, and
81
+ - 🤝 opportunities to mix and nest frameworks together
82
+
83
+ [**Client Directives**](https://docs.astro.build/en/reference/directives-reference/#client-directives) are still required in `.mdx` files.
84
+
85
+ > **Note**: `.mdx` files adhere to strict JSX syntax rather than Astro's HTML-like syntax.
86
+
87
+ ### Variables
88
+
89
+ MDX supports `export` statements to add variables to your templates. These variables are accessible both from the template itself _and_ as named properties when importing the template somewhere else.
90
+
91
+ For instance, you can export a `title` field from an MDX page or component to use as a heading with `{JSX expressions}`:
92
+
93
+ ```mdx
94
+ export const title = 'My first MDX post'
95
+
96
+ # {title}
97
+ ```
98
+
99
+ This `title` will be accessible from `import` and [glob](https://docs.astro.build/en/reference/api-reference/#astroglob) statements as well:
100
+
101
+ ```astro
102
+ ---
103
+ // src/pages/index.astro
104
+ const posts = await Astro.glob('./*.mdx');
105
+ ---
106
+
107
+ {posts.map(post => <p>{post.title}</p>)}
108
+ ```
109
+
110
+ See [the official "how MDX works" guide](https://mdxjs.com/docs/using-mdx/#how-mdx-works) for more on MDX variables.
111
+
112
+ ### Exported properties
113
+
114
+ Alongside your [MDX variable exports](#variables), we generate a few helpful exports as well. These are accessible when importing an MDX file via `import` statements or [`Astro.glob`](https://docs.astro.build/en/reference/api-reference/#astroglob).
115
+
116
+ #### `file`
117
+
118
+ The absolute path to the MDX file (e.g. `home/user/projects/.../file.md`).
119
+
120
+ #### `url`
121
+
122
+ The browser-ready URL for MDX files under `src/pages/`. For example, `src/pages/en/about.mdx` will provide a `url` of `/en/about/`. For MDX files outside of `src/pages`, `url` will be `undefined`.
123
+
124
+ #### `getHeadings()`
125
+
126
+ **Returns:** `{ depth: number; slug: string; text: string }[]`
127
+
128
+ A function that returns an array of all headings (i.e. `h1 -> h6` elements) in the MDX file. Each heading’s `slug` corresponds to the generated ID for a given heading and can be used for anchor links.
129
+
130
+ ### Frontmatter
131
+
132
+ Astro also supports YAML-based frontmatter out-of-the-box. By default, all variables declared in a frontmatter fence (`---`) will be accessible via the `frontmatter` export.
133
+
134
+ For example, we can add a `title` and `publishDate` to an MDX page or component like so:
135
+
136
+ ```mdx
137
+ ---
138
+ title: 'My first MDX post'
139
+ publishDate: '21 September 2022'
140
+ ---
141
+
142
+ # {frontmatter.title}
143
+ ```
144
+
145
+ Now, this `title` and `publishDate` will be accessible from `import` and [glob](https://docs.astro.build/en/reference/api-reference/#astroglob) statements via the `frontmatter` property. This matches the behavior of [plain markdown in Astro](https://docs.astro.build/en/reference/api-reference/#markdown-files) as well!
146
+
147
+ ```astro
148
+ ---
149
+ // src/pages/index.astro
150
+ const posts = await Astro.glob('./*.mdx');
151
+ ---
152
+
153
+ {posts.map(post => (
154
+ <Fragment>
155
+ <h2>{post.frontmatter.title}</h2>
156
+ <time>{post.frontmatter.publishDate}</time>
157
+ </Fragment>
158
+ ))}
159
+ ```
160
+
161
+ ### Inject frontmatter via remark or rehype plugins
162
+
163
+ You may want to inject frontmatter properties across all of your MDX files. By using a [remark](#remarkPlugins) or [rehype](#remarkplugins) plugin, you can generate these properties based on a file’s contents.
164
+
165
+ You can append to the `data.astro.frontmatter` property from your plugin’s `file` argument like so:
166
+
167
+ ```js
168
+ // example-remark-plugin.mjs
169
+ export function exampleRemarkPlugin() {
170
+ // All remark and rehype plugins return a separate function
171
+ return function (tree, file) {
172
+ file.data.astro.frontmatter.customProperty = 'Generated property';
173
+ }
174
+ }
175
+ ```
176
+
177
+ After applying this plugin to your MDX integration config:
178
+
179
+ ```js
180
+ // astro.config.mjs
181
+ import mdx from '@astrojs/mdx';
182
+ import { exampleRemarkPlugin } from './example-remark-plugin.mjs';
183
+
184
+ export default {
185
+ integrations: [
186
+ mdx({
187
+ remarkPlugins: [exampleRemarkPlugin],
188
+ }),
189
+ ],
190
+ };
191
+ ```
192
+
193
+ …every MDX file will have `customProperty` in its frontmatter! See [our Markdown documentation](https://docs.astro.build/en/guides/markdown-content/#injecting-frontmatter) for more usage instructions and a [reading time plugin example](https://docs.astro.build/en/guides/markdown-content/#example-calculate-reading-time).
194
+
195
+ ### Layouts
196
+
197
+ Layouts can be applied [in the same way as standard Astro Markdown](https://docs.astro.build/en/guides/markdown-content/#markdown-layouts). You can add a `layout` to [your frontmatter](#frontmatter) like so:
198
+
199
+ ```yaml
200
+ ---
201
+ layout: '../layouts/BaseLayout.astro'
202
+ title: 'My Blog Post'
203
+ ---
204
+ ```
205
+
206
+ Then, you can retrieve all other frontmatter properties from your layout via the `frontmatter` property, and render your MDX using the default [`<slot />`](https://docs.astro.build/en/core-concepts/astro-components/#slots). See [layout props](#layout-props) for a complete list of props available.
207
+
208
+ ```astro
209
+ ---
210
+ // src/layouts/BaseLayout.astro
211
+ const { frontmatter, url } = Astro.props;
212
+ ---
213
+ <html>
214
+ <head>
215
+ <meta rel="canonical" href={new URL(url, Astro.site).pathname}>
216
+ <title>{frontmatter.title}</title>
217
+ </head>
218
+ <body>
219
+ <h1>{frontmatter.title}</h1>
220
+ <!-- Rendered MDX will be passed into the default slot. -->
221
+ <slot />
222
+ </body>
223
+ </html>
224
+ ```
225
+
226
+ You can set a layout’s [`Props` type](/en/guides/typescript/#component-props) with the `MDXLayoutProps` helper.
227
+
228
+ :::note
229
+ `MDXLayoutProps` is the same as the `MarkdownLayoutProps` utility type with `rawContent()` and `compiledContent()` removed (since these are not available for `.mdx` files). Feel free to **use `MarkdownLayoutProps` instead** when sharing a layout across `.md` and `.mdx` files.
230
+ :::
231
+
232
+ ```astro ins={2,4-9}
233
+ ---
234
+ // src/layouts/BaseLayout.astro
235
+ import type { MDXLayoutProps } from 'astro';
236
+
237
+ type Props = MDXLayoutProps<{
238
+ // Define frontmatter props here
239
+ title: string;
240
+ author: string;
241
+ date: string;
242
+ }>;
243
+
244
+ // Now, `frontmatter`, `url`, and other MDX layout properties
245
+ // are accessible with type safety
246
+ const { frontmatter, url } = Astro.props;
247
+ ---
248
+ <html>
249
+ <head>
250
+ <meta rel="canonical" href={new URL(url, Astro.site).pathname}>
251
+ <title>{frontmatter.title}</title>
252
+ </head>
253
+ <body>
254
+ <h1>{frontmatter.title}</h1>
255
+ <slot />
256
+ </body>
257
+ </html>
258
+ ```
259
+
260
+ #### Layout props
261
+
262
+ All [exported properties](#exported-properties) are available from `Astro.props` in your layout, **with two key differences:**
263
+ - Heading information (i.e. `h1 -> h6` elements) is available via the `headings` array, rather than a `getHeadings()` function.
264
+ - `file` and `url` are _also_ available as nested `frontmatter` properties (i.e. `frontmatter.url` and `frontmatter.file`). This is consistent with Astro's Markdown layout properties.
265
+
266
+ Astro recommends using the `MDXLayoutProps` type (see previous section) to explore all available properties.
267
+
268
+ #### Importing layouts manually
269
+
270
+ You may need to pass information to your layouts that does not (or cannot) exist in your frontmatter. In this case, you can import and use a [`<Layout />` component](https://docs.astro.build/en/core-concepts/layouts/) like any other component:
271
+
272
+ ```mdx
273
+ ---
274
+ // src/pages/posts/first-post.mdx
275
+
276
+ title: 'My first MDX post'
277
+ publishDate: '21 September 2022'
278
+ ---
279
+ import BaseLayout from '../layouts/BaseLayout.astro';
280
+
281
+ function fancyJsHelper() {
282
+ return "Try doing that with YAML!";
283
+ }
284
+
285
+ <BaseLayout title={frontmatter.title} fancyJsHelper={fancyJsHelper}>
286
+ Welcome to my new Astro blog, using MDX!
287
+ </BaseLayout>
288
+ ```
289
+ Then, your values are available to you through `Astro.props` in your layout, and your MDX content will be injected into the page where your `<slot />` component is written:
290
+
291
+ ```astro
292
+ ---
293
+ // src/layouts/BaseLayout.astro
294
+ const { title, fancyJsHelper } = Astro.props;
295
+ ---
296
+ <!-- -->
297
+ <h1>{title}</h1>
298
+ <slot />
299
+ <p>{fancyJsHelper()}</p>
300
+ <!-- -->
301
+ ```
302
+
303
+ ### Custom components
304
+
305
+ Under the hood, MDX will convert Markdown into HTML components. For example, this blockquote:
306
+
307
+ ```md
308
+ > A blockquote with *some* emphasis.
309
+ ```
310
+
311
+ will be converted into this HTML:
312
+
313
+ ```html
314
+ <blockquote>
315
+ <p>A blockquote with <em>some</em> emphasis.</p>
316
+ </blockquote>
317
+ ```
318
+
319
+ But what if you want to specify your own markup for these blockquotes? In the above example, you could create a custom `<Blockquote />` component (in any language) that either has a `<slot />` component or accepts a `children` prop.
320
+
321
+ ```astro title="src/components/Blockquote.astro"
322
+ <blockquote class="bg-blue-50 p-4">
323
+ <span class="text-4xl text-blue-600 mb-2">“</span>
324
+ <slot />
325
+ </blockquote>
326
+ ```
327
+
328
+ Then in the MDX file you import the component and export it to the `components` export.
329
+
330
+ ```mdx title="src/pages/posts/post-1.mdx" {2}
331
+ import Blockquote from '../components/Blockquote.astro';
332
+ export const components = { blockquote: Blockquote };
333
+ ```
334
+
335
+ Now, writing the standard Markdown blockquote syntax (`>`) will use your custom `<Blockquote />` component instead. No need to use a component in Markdown, or write a remark/rehype plugin! Visit the [MDX website](https://mdxjs.com/table-of-components/) for a full list of HTML elements that can be overwritten as custom components.
336
+
337
+
338
+ #### Custom components with imported `mdx`
339
+
340
+ When rendering imported MDX content, custom components can also be passed via the `components` prop:
341
+
342
+ ```astro title="src/pages/page.astro" "components={{ h1: Heading }}"
343
+ ---
344
+ import Content from '../content.mdx';
345
+ import Heading from '../Heading.astro';
346
+ ---
347
+
348
+ <Content components={{ h1: Heading }} />
349
+ ```
350
+
351
+ ### Syntax highlighting
352
+
353
+ The MDX integration respects [your project's `markdown.syntaxHighlight` configuration](https://docs.astro.build/en/guides/markdown-content/#syntax-highlighting).
354
+
355
+ We will highlight your code blocks with [Shiki](https://github.com/shikijs/shiki) by default. You can customize this highlighter using the `markdown.shikiConfig` option in your `astro.config`. For example, you can apply a different built-in theme like so:
356
+
357
+ ```js
358
+ // astro.config.mjs
359
+ export default {
360
+ markdown: {
361
+ shikiConfig: {
362
+ theme: 'dracula',
363
+ },
364
+ },
365
+ integrations: [mdx()],
366
+ }
367
+ ```
368
+
369
+ Visit [our Shiki configuration docs](https://docs.astro.build/en/guides/markdown-content/#shiki-configuration) for more on using Shiki with Astro.
370
+
371
+ #### Switch to Prism
372
+
373
+ You can also use the [Prism](https://prismjs.com/) syntax highlighter by setting `markdown.syntaxHighlight` to `'prism'` in your `astro.config` like so:
374
+
375
+ ```js
376
+ // astro.config.mjs
377
+ export default {
378
+ markdown: {
379
+ syntaxHighlight: 'prism',
380
+ },
381
+ integrations: [mdx()],
382
+ }
383
+ ```
384
+
385
+ This applies a minimal Prism renderer with added support for `astro` code blocks. Visit [our "Prism configuration" docs](https://docs.astro.build/en/guides/markdown-content/#prism-configuration) for more on using Prism with Astro.
386
+
387
+ #### Switch to a custom syntax highlighter
388
+
389
+ You may want to apply your own syntax highlighter too. If your highlighter offers a remark or rehype plugin, you can flip off our syntax highlighting by setting `markdown.syntaxHighlight: false` and wiring up your plugin. For example, say you want to apply [Shiki Twoslash's remark plugin](https://www.npmjs.com/package/remark-shiki-twoslash):
390
+
391
+ ```js
392
+ // astro.config.mjs
393
+ import shikiTwoslash from 'remark-shiki-twoslash';
394
+
395
+ export default {
396
+ markdown: {
397
+ syntaxHighlight: false,
398
+ },
399
+ integrations: [mdx({
400
+ remarkPlugins: [shikiTwoslash, { /* Shiki Twoslash config */ }],
401
+ })],
402
+ ```
403
+
404
+ ## Configuration
405
+
406
+ ### remarkPlugins
407
+
408
+ [Remark plugins](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) allow you to extend your Markdown with new capabilities. This includes [auto-generating a table of contents](https://github.com/remarkjs/remark-toc), [applying accessible emoji labels](https://github.com/florianeckerstorfer/remark-a11y-emoji), and more. We encourage you to browse [awesome-remark](https://github.com/remarkjs/awesome-remark) for a full curated list!
409
+
410
+ This example applies the [`remark-toc`](https://github.com/remarkjs/remark-toc) plugin to `.mdx` files. To customize plugin inheritance from your Markdown config or Astro's defaults, [see the `extendPlugins` option](#extendPlugins).
411
+
412
+ ```js
413
+ // astro.config.mjs
414
+ import remarkToc from 'remark-toc';
415
+
416
+ export default {
417
+ integrations: [mdx({
418
+ remarkPlugins: [remarkToc],
419
+ })],
420
+ }
421
+ ```
422
+
423
+ ### rehypePlugins
424
+
425
+ [Rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) allow you to transform the HTML that your Markdown generates. We encourage you to browse [awesome-rehype](https://github.com/rehypejs/awesome-rehype) for a full curated list of plugins!
426
+
427
+ We apply our own (non-removable) [`collect-headings`](https://github.com/withastro/astro/blob/main/packages/integrations/mdx/src/rehype-collect-headings.ts) plugin. This applies IDs to all headings (i.e. `h1 -> h6`) in your MDX files to [link to headings via anchor tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#linking_to_an_element_on_the_same_page).
428
+
429
+ This example applies the [`rehype-minify`](https://github.com/rehypejs/rehype-minify) plugin to `.mdx` files. To customize plugin inheritance from your Markdown config or Astro's defaults, [see the `extendPlugins` option](#extendPlugins).
430
+
431
+ ```js
432
+ // astro.config.mjs
433
+ import rehypeMinifyHtml from 'rehype-minify';
434
+
435
+ export default {
436
+ integrations: [mdx({
437
+ rehypePlugins: [rehypeMinifyHtml],
438
+ })],
439
+ }
440
+ ```
441
+
442
+ ### extendPlugins
443
+
444
+ **Type:** `'markdown' | 'astroDefaults' | false`
445
+
446
+ **Default:** `'markdown'`
447
+
448
+ #### `markdown` (default)
449
+
450
+ By default, Astro inherits all [remark](#remarkPlugins) and [rehype](#rehypePlugins) plugins from [the `markdown` option in your Astro config](https://docs.astro.build/en/guides/markdown-content/#markdown-plugins). This also respects the [`markdown.extendDefaultPlugins`](https://docs.astro.build/en/reference/configuration-reference/#markdownextenddefaultplugins) option to extend Astro's defaults. Any additional plugins you apply in your MDX config will be applied _after_ your configured Markdown plugins.
451
+
452
+ This example applies [`remark-toc`](https://github.com/remarkjs/remark-toc) to Markdown _and_ MDX, and [`rehype-minify`](https://github.com/rehypejs/rehype-minify) to MDX alone:
453
+
454
+ ```js
455
+ // astro.config.mjs
456
+ import remarkToc from 'remark-toc';
457
+ import rehypeMinify from 'rehype-minify';
458
+
459
+ export default {
460
+ markdown: {
461
+ // Applied to .md and .mdx files
462
+ remarkPlugins: [remarkToc],
463
+ },
464
+ integrations: [mdx({
465
+ // Applied to .mdx files only
466
+ rehypePlugins: [rehypeMinify],
467
+ })],
468
+ }
469
+ ```
470
+
471
+ #### `astroDefaults`
472
+
473
+ You may _only_ want to extend [Astro's default plugins](https://docs.astro.build/en/reference/configuration-reference/#markdownextenddefaultplugins) without inheriting your Markdown config. This example will apply the default [GitHub-Flavored Markdown](https://github.com/remarkjs/remark-gfm) and [Smartypants](https://github.com/silvenon/remark-smartypants) plugins alongside [`remark-toc`](https://github.com/remarkjs/remark-toc):
474
+
475
+ ```js "extendPlugins: 'astroDefaults'"
476
+ // astro.config.mjs
477
+ import remarkToc from 'remark-toc';
478
+
479
+ export default {
480
+ markdown: {
481
+ remarkPlugins: [/** ignored */]
482
+ },
483
+ integrations: [mdx({
484
+ remarkPlugins: [remarkToc],
485
+ // Astro defaults applied
486
+ extendPlugins: 'astroDefaults',
487
+ })],
488
+ }
489
+ ```
490
+
491
+ #### `false`
492
+
493
+ If you don't want to extend any plugins, set `extendPlugins` to `false`:
494
+
495
+ ```js "extendPlugins: false"
496
+ // astro.config.mjs
497
+ import remarkToc from 'remark-toc';
498
+
499
+ export default {
500
+ integrations: [mdx({
501
+ remarkPlugins: [remarkToc],
502
+ // Astro defaults not applied
503
+ extendPlugins: false,
504
+ })],
505
+ }
506
+ ```
507
+
508
+ ## Examples
509
+
510
+ - The [Astro MDX example](https://github.com/withastro/astro/tree/latest/examples/with-mdx) shows how to use MDX files in your Astro project.
511
+
512
+ ## Troubleshooting
513
+
514
+ For help, check out the `#support` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
515
+
516
+ You can also check our [Astro Integration Documentation][astro-integration] for more on integrations.
517
+
518
+ ## Contributing
519
+
520
+ This package is maintained by Astro's Core team. You're welcome to submit an issue or PR!
521
+
522
+ ## Changelog
523
+
524
+ See [CHANGELOG.md](CHANGELOG.md) for a history of changes to this integration.
525
+
526
+ [astro-integration]: https://docs.astro.build/en/guides/integrations-guide/
527
+ [astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components
@@ -0,0 +1,15 @@
1
+ import { PluggableList } from '@mdx-js/mdx/lib/core.js';
2
+ import type { AstroIntegration } from 'astro';
3
+ export declare type MdxOptions = {
4
+ remarkPlugins?: PluggableList;
5
+ rehypePlugins?: PluggableList;
6
+ /**
7
+ * Choose which remark and rehype plugins to inherit, if any.
8
+ *
9
+ * - "markdown" (default) - inherit your project’s markdown plugin config ([see Markdown docs](https://docs.astro.build/en/guides/markdown-content/#configuring-markdown))
10
+ * - "astroDefaults" - inherit Astro’s default plugins only ([see defaults](https://docs.astro.build/en/reference/configuration-reference/#markdownextenddefaultplugins))
11
+ * - false - do not inherit any plugins
12
+ */
13
+ extendPlugins?: 'markdown' | 'astroDefaults' | false;
14
+ };
15
+ export default function mdx(mdxOptions?: MdxOptions): AstroIntegration;
package/dist/index.js ADDED
@@ -0,0 +1,131 @@
1
+ import { compile as mdxCompile } from "@mdx-js/mdx";
2
+ import mdxPlugin from "@mdx-js/rollup";
3
+ import { parse as parseESM } from "es-module-lexer";
4
+ import { blue, bold } from "kleur/colors";
5
+ import fs from "node:fs/promises";
6
+ import { VFile } from "vfile";
7
+ import {
8
+ getRehypePlugins,
9
+ getRemarkPlugins,
10
+ recmaInjectImportMetaEnvPlugin,
11
+ rehypeApplyFrontmatterExport
12
+ } from "./plugins.js";
13
+ import { getFileInfo, handleExtendsNotSupported, parseFrontmatter } from "./utils.js";
14
+ const RAW_CONTENT_ERROR = "MDX does not support rawContent()! If you need to read the Markdown contents to calculate values (ex. reading time), we suggest injecting frontmatter via remark plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins";
15
+ const COMPILED_CONTENT_ERROR = "MDX does not support compiledContent()! If you need to read the HTML contents to calculate values (ex. reading time), we suggest injecting frontmatter via rehype plugins. Learn more on our docs: https://docs.astro.build/en/guides/integrations-guide/mdx/#inject-frontmatter-via-remark-or-rehype-plugins";
16
+ function mdx(mdxOptions = {}) {
17
+ return {
18
+ name: "@astrojs/mdx",
19
+ hooks: {
20
+ "astro:config:setup": async ({ updateConfig, config, addPageExtension, command }) => {
21
+ var _a, _b;
22
+ addPageExtension(".mdx");
23
+ mdxOptions.extendPlugins ?? (mdxOptions.extendPlugins = "markdown");
24
+ handleExtendsNotSupported(mdxOptions.remarkPlugins);
25
+ handleExtendsNotSupported(mdxOptions.rehypePlugins);
26
+ if (mdxOptions.extendPlugins === "markdown" && (((_a = config.markdown.rehypePlugins) == null ? void 0 : _a.length) || ((_b = config.markdown.remarkPlugins) == null ? void 0 : _b.length))) {
27
+ console.log(
28
+ blue(`[MDX] Now inheriting remark and rehype plugins from "markdown" config.`)
29
+ );
30
+ console.log(
31
+ `If you applied a plugin to both your Markdown and MDX configs, we suggest ${bold(
32
+ "removing the duplicate MDX entry."
33
+ )}`
34
+ );
35
+ console.log(`See "extendPlugins" option to configure this behavior.`);
36
+ }
37
+ const mdxPluginOpts = {
38
+ remarkPlugins: await getRemarkPlugins(mdxOptions, config),
39
+ rehypePlugins: getRehypePlugins(mdxOptions, config),
40
+ jsx: true,
41
+ jsxImportSource: "astro",
42
+ format: "mdx",
43
+ mdExtensions: []
44
+ };
45
+ let importMetaEnv = {
46
+ SITE: config.site
47
+ };
48
+ updateConfig({
49
+ vite: {
50
+ plugins: [
51
+ {
52
+ enforce: "pre",
53
+ ...mdxPlugin(mdxPluginOpts),
54
+ configResolved(resolved) {
55
+ importMetaEnv = { ...importMetaEnv, ...resolved.env };
56
+ },
57
+ async transform(_, id) {
58
+ if (!id.endsWith("mdx"))
59
+ return;
60
+ const { fileId } = getFileInfo(id, config);
61
+ const code = await fs.readFile(fileId, "utf-8");
62
+ const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
63
+ const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
64
+ ...mdxPluginOpts,
65
+ rehypePlugins: [
66
+ ...mdxPluginOpts.rehypePlugins ?? [],
67
+ () => rehypeApplyFrontmatterExport(frontmatter)
68
+ ],
69
+ recmaPlugins: [() => recmaInjectImportMetaEnvPlugin({ importMetaEnv })]
70
+ });
71
+ return {
72
+ code: escapeViteEnvReferences(String(compiled.value)),
73
+ map: compiled.map
74
+ };
75
+ }
76
+ },
77
+ {
78
+ name: "@astrojs/mdx-postprocess",
79
+ transform(code, id) {
80
+ if (!id.endsWith(".mdx"))
81
+ return;
82
+ code += `
83
+ MDXContent[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
84
+ const [, moduleExports] = parseESM(code);
85
+ const { fileUrl, fileId } = getFileInfo(id, config);
86
+ if (!moduleExports.includes("url")) {
87
+ code += `
88
+ export const url = ${JSON.stringify(fileUrl)};`;
89
+ }
90
+ if (!moduleExports.includes("file")) {
91
+ code += `
92
+ export const file = ${JSON.stringify(fileId)};`;
93
+ }
94
+ if (!moduleExports.includes("rawContent")) {
95
+ code += `
96
+ export function rawContent() { throw new Error(${JSON.stringify(
97
+ RAW_CONTENT_ERROR
98
+ )}) };`;
99
+ }
100
+ if (!moduleExports.includes("compiledContent")) {
101
+ code += `
102
+ export function compiledContent() { throw new Error(${JSON.stringify(
103
+ COMPILED_CONTENT_ERROR
104
+ )}) };`;
105
+ }
106
+ if (!moduleExports.includes("Content")) {
107
+ code += `
108
+ export const Content = MDXContent;`;
109
+ }
110
+ if (command === "dev") {
111
+ code += `
112
+ if (import.meta.hot) {
113
+ import.meta.hot.decline();
114
+ }`;
115
+ }
116
+ return escapeViteEnvReferences(code);
117
+ }
118
+ }
119
+ ]
120
+ }
121
+ });
122
+ }
123
+ }
124
+ };
125
+ }
126
+ function escapeViteEnvReferences(code) {
127
+ return code.replace(/import\.meta\.env/g, "import\\u002Emeta.env");
128
+ }
129
+ export {
130
+ mdx as default
131
+ };
@@ -0,0 +1,11 @@
1
+ import type { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
2
+ import type { AstroConfig } from 'astro';
3
+ import type { VFile } from 'vfile';
4
+ import { MdxOptions } from './index.js';
5
+ export declare function recmaInjectImportMetaEnvPlugin({ importMetaEnv, }: {
6
+ importMetaEnv: Record<string, any>;
7
+ }): (tree: any) => void;
8
+ export declare function remarkInitializeAstroData(): (tree: any, vfile: VFile) => void;
9
+ export declare function rehypeApplyFrontmatterExport(pageFrontmatter: Record<string, any>): (tree: any, vfile: VFile) => void;
10
+ export declare function getRemarkPlugins(mdxOptions: MdxOptions, config: AstroConfig): Promise<MdxRollupPluginOptions['remarkPlugins']>;
11
+ export declare function getRehypePlugins(mdxOptions: MdxOptions, config: AstroConfig): MdxRollupPluginOptions['rehypePlugins'];