@astrojs/mdx 1.0.0-beta.2 → 1.0.0-rc.2
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.
- package/README.md +82 -18
- package/dist/index.d.ts +4 -2
- package/dist/index.js +83 -35
- package/dist/plugins.d.ts +4 -5
- package/dist/plugins.js +36 -80
- package/dist/rehype-collect-headings.d.ts +1 -1
- package/dist/rehype-meta-string.js +2 -3
- package/dist/rehype-optimize-static.d.ts +11 -0
- package/dist/rehype-optimize-static.js +62 -0
- package/dist/remark-images-to-component.d.ts +2 -0
- package/dist/remark-images-to-component.js +83 -0
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +23 -15
- package/package.json +36 -26
- package/template/content-module-types.d.ts +9 -0
- package/.turbo/turbo-build.log +0 -5
- package/CHANGELOG.md +0 -469
- package/src/index.ts +0 -201
- package/src/plugins.ts +0 -246
- package/src/rehype-collect-headings.ts +0 -11
- package/src/rehype-meta-string.ts +0 -17
- package/src/remark-prism.ts +0 -18
- package/src/remark-shiki.ts +0 -95
- package/src/utils.ts +0 -102
- package/test/fixtures/mdx-astro-markdown-remarkRehype/src/pages/index.mdx +0 -5
- package/test/fixtures/mdx-component/src/components/Test.mdx +0 -3
- package/test/fixtures/mdx-component/src/components/WithFragment.mdx +0 -3
- package/test/fixtures/mdx-component/src/pages/glob.astro +0 -20
- package/test/fixtures/mdx-component/src/pages/index.astro +0 -5
- package/test/fixtures/mdx-component/src/pages/w-fragment.astro +0 -5
- package/test/fixtures/mdx-escape/src/components/Em.astro +0 -7
- package/test/fixtures/mdx-escape/src/components/P.astro +0 -1
- package/test/fixtures/mdx-escape/src/components/Title.astro +0 -1
- package/test/fixtures/mdx-escape/src/pages/html-tag.mdx +0 -5
- package/test/fixtures/mdx-escape/src/pages/index.mdx +0 -13
- package/test/fixtures/mdx-frontmatter/src/layouts/Base.astro +0 -38
- package/test/fixtures/mdx-frontmatter/src/pages/glob.json.js +0 -9
- package/test/fixtures/mdx-frontmatter/src/pages/index.mdx +0 -10
- package/test/fixtures/mdx-frontmatter/src/pages/with-headings.mdx +0 -7
- package/test/fixtures/mdx-frontmatter-injection/astro.config.mjs +0 -12
- package/test/fixtures/mdx-frontmatter-injection/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-frontmatter-injection/package.json +0 -12
- package/test/fixtures/mdx-frontmatter-injection/src/layouts/Base.astro +0 -17
- package/test/fixtures/mdx-frontmatter-injection/src/markdown-plugins.mjs +0 -27
- package/test/fixtures/mdx-frontmatter-injection/src/pages/glob.json.js +0 -6
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-1.mdx +0 -8
- package/test/fixtures/mdx-frontmatter-injection/src/pages/page-2.mdx +0 -24
- package/test/fixtures/mdx-get-headings/src/pages/pages.json.js +0 -11
- package/test/fixtures/mdx-get-headings/src/pages/test-with-jsx-expressions.mdx +0 -8
- package/test/fixtures/mdx-get-headings/src/pages/test.mdx +0 -9
- package/test/fixtures/mdx-get-static-paths/src/content/1.mdx +0 -5
- package/test/fixtures/mdx-get-static-paths/src/pages/[slug].astro +0 -34
- package/test/fixtures/mdx-infinite-loop/astro.config.ts +0 -6
- package/test/fixtures/mdx-infinite-loop/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-infinite-loop/package.json +0 -10
- package/test/fixtures/mdx-infinite-loop/src/components/Test.js +0 -3
- package/test/fixtures/mdx-infinite-loop/src/pages/doc.mdx +0 -6
- package/test/fixtures/mdx-infinite-loop/src/pages/index.astro +0 -5
- package/test/fixtures/mdx-namespace/astro.config.mjs +0 -6
- package/test/fixtures/mdx-namespace/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-namespace/package.json +0 -10
- package/test/fixtures/mdx-namespace/src/components/Component.jsx +0 -6
- package/test/fixtures/mdx-namespace/src/pages/object.mdx +0 -3
- package/test/fixtures/mdx-namespace/src/pages/star.mdx +0 -3
- package/test/fixtures/mdx-page/astro.config.ts +0 -5
- package/test/fixtures/mdx-page/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-page/package.json +0 -9
- package/test/fixtures/mdx-page/src/pages/index.mdx +0 -3
- package/test/fixtures/mdx-page/src/styles.css +0 -3
- package/test/fixtures/mdx-plugins/src/pages/with-plugins.mdx +0 -25
- package/test/fixtures/mdx-plus-react/astro.config.mjs +0 -6
- package/test/fixtures/mdx-plus-react/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-plus-react/package.json +0 -10
- package/test/fixtures/mdx-plus-react/src/components/Component.jsx +0 -5
- package/test/fixtures/mdx-plus-react/src/pages/index.astro +0 -11
- package/test/fixtures/mdx-slots/src/components/Slotted.astro +0 -4
- package/test/fixtures/mdx-slots/src/components/Test.mdx +0 -15
- package/test/fixtures/mdx-slots/src/pages/glob.astro +0 -11
- package/test/fixtures/mdx-slots/src/pages/index.astro +0 -5
- package/test/fixtures/mdx-syntax-hightlighting/src/pages/index.mdx +0 -9
- package/test/fixtures/mdx-url-export/src/pages/pages.json.js +0 -9
- package/test/fixtures/mdx-url-export/src/pages/test-1.mdx +0 -1
- package/test/fixtures/mdx-url-export/src/pages/test-2.mdx +0 -1
- package/test/fixtures/mdx-url-export/src/pages/with-url-override.mdx +0 -3
- package/test/fixtures/mdx-vite-env-vars/astro.config.mjs +0 -9
- package/test/fixtures/mdx-vite-env-vars/node_modules/.bin/astro +0 -17
- package/test/fixtures/mdx-vite-env-vars/package.json +0 -7
- package/test/fixtures/mdx-vite-env-vars/src/pages/frontmatter.json.js +0 -7
- package/test/fixtures/mdx-vite-env-vars/src/pages/vite-env-vars.mdx +0 -38
- package/test/mdx-astro-markdown-remarkRehype.test.js +0 -85
- package/test/mdx-component.test.js +0 -191
- package/test/mdx-escape.test.js +0 -32
- package/test/mdx-frontmatter-injection.test.js +0 -53
- package/test/mdx-frontmatter.test.js +0 -77
- package/test/mdx-get-headings.test.js +0 -151
- package/test/mdx-get-static-paths.test.js +0 -32
- package/test/mdx-infinite-loop.test.js +0 -30
- package/test/mdx-namespace.test.js +0 -83
- package/test/mdx-page.test.js +0 -64
- package/test/mdx-plugins.test.js +0 -250
- package/test/mdx-plus-react.test.js +0 -25
- package/test/mdx-slots.js +0 -124
- package/test/mdx-syntax-highlighting.test.js +0 -145
- package/test/mdx-url-export.test.js +0 -28
- package/test/mdx-vite-env-vars.test.js +0 -54
- package/tsconfig.json +0 -10
package/README.md
CHANGED
|
@@ -42,9 +42,8 @@ npm install @astrojs/mdx
|
|
|
42
42
|
|
|
43
43
|
Then, apply this integration to your `astro.config.*` file using the `integrations` property:
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
```js
|
|
45
|
+
```js ins={3} "mdx()"
|
|
46
|
+
// astro.config.mjs
|
|
48
47
|
import { defineConfig } from 'astro/config';
|
|
49
48
|
import mdx from '@astrojs/mdx';
|
|
50
49
|
|
|
@@ -59,14 +58,16 @@ export default defineConfig({
|
|
|
59
58
|
[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.
|
|
60
59
|
|
|
61
60
|
```json title=".vscode/settings.json"
|
|
62
|
-
|
|
61
|
+
{
|
|
62
|
+
"files.associations": {
|
|
63
63
|
"*.mdx": "markdown"
|
|
64
|
+
}
|
|
64
65
|
}
|
|
65
66
|
```
|
|
66
67
|
|
|
67
68
|
## Usage
|
|
68
69
|
|
|
69
|
-
With the Astro MDX integration, 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. You can also [import `.mdx` files](https://docs.astro.build/en/guides/markdown-content/#importing-markdown) into `.astro` files.
|
|
70
|
+
With the Astro MDX integration, 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. You can also [import `.mdx` files](https://docs.astro.build/en/guides/markdown-content/#importing-markdown) into `.astro` files.
|
|
70
71
|
|
|
71
72
|
Astro's MDX integration adds extra features to standard MDX, including Markdown-style frontmatter. This allows you to use most of Astro's built-in Markdown features like a [special frontmatter `layout` property](https://docs.astro.build/en/guides/markdown-content/#frontmatter-layout) and a [property for marking a page as a draft](https://docs.astro.build/en/guides/markdown-content/#draft-pages).
|
|
72
73
|
|
|
@@ -83,16 +84,17 @@ You can configure how your MDX is rendered with the following options:
|
|
|
83
84
|
- [Options inherited from Markdown config](#options-inherited-from-markdown-config)
|
|
84
85
|
- [`extendMarkdownConfig`](#extendmarkdownconfig)
|
|
85
86
|
- [`recmaPlugins`](#recmaplugins)
|
|
87
|
+
- [`optimize`](#optimize)
|
|
86
88
|
|
|
87
89
|
### Options inherited from Markdown config
|
|
88
90
|
|
|
89
91
|
All [`markdown` configuration options](https://docs.astro.build/en/reference/configuration-reference/#markdown-options) except `drafts` can be configured separately in the MDX integration. This includes remark and rehype plugins, syntax highlighting, and more. Options will default to those in your Markdown config ([see the `extendMarkdownConfig` option](#extendmarkdownconfig) to modify this).
|
|
90
92
|
|
|
91
93
|
:::note
|
|
92
|
-
There is no separate MDX configuration for [including pages marked as draft in the build](https://docs.astro.build/en/reference/configuration-reference/#markdowndrafts). This Markdown setting will be respected by both Markdown and MDX files and cannot be
|
|
94
|
+
There is no separate MDX configuration for [including pages marked as draft in the build](https://docs.astro.build/en/reference/configuration-reference/#markdowndrafts). This Markdown setting will be respected by both Markdown and MDX files and cannot be overridden for MDX files specifically.
|
|
93
95
|
:::
|
|
94
96
|
|
|
95
|
-
```
|
|
97
|
+
```js
|
|
96
98
|
// astro.config.mjs
|
|
97
99
|
import { defineConfig } from 'astro/config';
|
|
98
100
|
import mdx from '@astrojs/mdx';
|
|
@@ -108,9 +110,9 @@ export default defineConfig({
|
|
|
108
110
|
rehypePlugins: [rehypeMinifyHtml],
|
|
109
111
|
remarkRehype: { footnoteLabel: 'Footnotes' },
|
|
110
112
|
gfm: false,
|
|
111
|
-
})
|
|
112
|
-
]
|
|
113
|
-
})
|
|
113
|
+
}),
|
|
114
|
+
],
|
|
115
|
+
});
|
|
114
116
|
```
|
|
115
117
|
|
|
116
118
|
:::caution
|
|
@@ -128,7 +130,7 @@ MDX will extend [your project's existing Markdown configuration](https://docs.as
|
|
|
128
130
|
|
|
129
131
|
For example, say you need to disable GitHub-Flavored Markdown and apply a different set of remark plugins for MDX files. You can apply these options like so, with `extendMarkdownConfig` enabled by default:
|
|
130
132
|
|
|
131
|
-
```
|
|
133
|
+
```js
|
|
132
134
|
// astro.config.mjs
|
|
133
135
|
import { defineConfig } from 'astro/config';
|
|
134
136
|
import mdx from '@astrojs/mdx';
|
|
@@ -148,14 +150,14 @@ export default defineConfig({
|
|
|
148
150
|
remarkPlugins: [remarkPlugin2],
|
|
149
151
|
// `gfm` overridden to `false`
|
|
150
152
|
gfm: false,
|
|
151
|
-
})
|
|
152
|
-
]
|
|
153
|
+
}),
|
|
154
|
+
],
|
|
153
155
|
});
|
|
154
156
|
```
|
|
155
157
|
|
|
156
158
|
You may also need to disable `markdown` config extension in MDX. For this, set `extendMarkdownConfig` to `false`:
|
|
157
159
|
|
|
158
|
-
```
|
|
160
|
+
```js
|
|
159
161
|
// astro.config.mjs
|
|
160
162
|
import { defineConfig } from 'astro/config';
|
|
161
163
|
import mdx from '@astrojs/mdx';
|
|
@@ -169,8 +171,8 @@ export default defineConfig({
|
|
|
169
171
|
// Markdown config now ignored
|
|
170
172
|
extendMarkdownConfig: false,
|
|
171
173
|
// No `remarkPlugins` applied
|
|
172
|
-
})
|
|
173
|
-
]
|
|
174
|
+
}),
|
|
175
|
+
],
|
|
174
176
|
});
|
|
175
177
|
```
|
|
176
178
|
|
|
@@ -180,9 +182,72 @@ These are plugins that modify the output [estree](https://github.com/estree/estr
|
|
|
180
182
|
|
|
181
183
|
We suggest [using AST Explorer](https://astexplorer.net/) to play with estree outputs, and trying [`estree-util-visit`](https://unifiedjs.com/explore/package/estree-util-visit/) for searching across JavaScript nodes.
|
|
182
184
|
|
|
185
|
+
### `optimize`
|
|
186
|
+
|
|
187
|
+
- **Type:** `boolean | { customComponentNames?: string[] }`
|
|
188
|
+
|
|
189
|
+
This is an optional configuration setting to optimize the MDX output for faster builds and rendering via an internal rehype plugin. This may be useful if you have many MDX files and notice slow builds. However, this option may generate some unescaped HTML, so make sure your site's interactive parts still work correctly after enabling it.
|
|
190
|
+
|
|
191
|
+
This is disabled by default. To enable MDX optimization, add the following to your MDX integration configuration:
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
// astro.config.mjs
|
|
195
|
+
import { defineConfig } from 'astro/config';
|
|
196
|
+
import mdx from '@astrojs/mdx';
|
|
197
|
+
|
|
198
|
+
export default defineConfig({
|
|
199
|
+
integrations: [
|
|
200
|
+
mdx({
|
|
201
|
+
optimize: true,
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### `customComponentNames`
|
|
208
|
+
|
|
209
|
+
- **Type:** `string[]`
|
|
210
|
+
|
|
211
|
+
An optional property of `optimize` to prevent the MDX optimizer from handling any [custom components passed to imported MDX content via the components prop](https://docs.astro.build/en/guides/markdown-content/#custom-components-with-imported-mdx).
|
|
212
|
+
|
|
213
|
+
You will need to exclude these components from optimization as the optimizer eagerly converts content into a static string, which will break custom components that needs to be dynamically rendered.
|
|
214
|
+
|
|
215
|
+
For example, the intended MDX output of the following is `<Heading>...</Heading>` in place of every `"<h1>...</h1>"`:
|
|
216
|
+
|
|
217
|
+
```astro
|
|
218
|
+
---
|
|
219
|
+
import { Content, components } from '../content.mdx';
|
|
220
|
+
import Heading from '../Heading.astro';
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
<Content components={{ ...components, h1: Heading }} />
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
To configure optimization for this using the `customComponentNames` property, specify an array of HTML element names that should be treated as custom components:
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
// astro.config.mjs
|
|
230
|
+
import { defineConfig } from 'astro/config';
|
|
231
|
+
import mdx from '@astrojs/mdx';
|
|
232
|
+
|
|
233
|
+
export default defineConfig({
|
|
234
|
+
integrations: [
|
|
235
|
+
mdx({
|
|
236
|
+
optimize: {
|
|
237
|
+
// Prevent the optimizer from handling `h1` elements
|
|
238
|
+
// These will be treated as custom components
|
|
239
|
+
customComponentNames: ['h1'],
|
|
240
|
+
},
|
|
241
|
+
}),
|
|
242
|
+
],
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Note that if your MDX file [configures custom components using `export const components = { ... }`](https://docs.astro.build/en/guides/markdown-content/#assigning-custom-components-to-html-elements), then you do not need to manually configure this option. The optimizer will automatically detect them.
|
|
247
|
+
|
|
183
248
|
## Examples
|
|
184
249
|
|
|
185
|
-
|
|
250
|
+
- The [Astro MDX starter template](https://github.com/withastro/astro/tree/latest/examples/with-mdx) shows how to use MDX files in your Astro project.
|
|
186
251
|
|
|
187
252
|
## Troubleshooting
|
|
188
253
|
|
|
@@ -199,5 +264,4 @@ This package is maintained by Astro's Core team. You're welcome to submit an iss
|
|
|
199
264
|
See [CHANGELOG.md](https://github.com/withastro/astro/tree/main/packages/integrations/mdx/CHANGELOG.md) for a history of changes to this integration.
|
|
200
265
|
|
|
201
266
|
[astro-integration]: https://docs.astro.build/en/guides/integrations-guide/
|
|
202
|
-
|
|
203
267
|
[astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
|
|
2
|
-
import { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
2
|
+
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
3
3
|
import type { AstroIntegration } from 'astro';
|
|
4
4
|
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
|
5
|
-
|
|
5
|
+
import type { OptimizeOptions } from './rehype-optimize-static.js';
|
|
6
|
+
export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
|
|
6
7
|
extendMarkdownConfig: boolean;
|
|
7
8
|
recmaPlugins: PluggableList;
|
|
8
9
|
remarkPlugins: PluggableList;
|
|
9
10
|
rehypePlugins: PluggableList;
|
|
10
11
|
remarkRehype: RemarkRehypeOptions;
|
|
12
|
+
optimize: boolean | OptimizeOptions;
|
|
11
13
|
};
|
|
12
14
|
export default function mdx(partialMdxOptions?: Partial<MdxOptions>): AstroIntegration;
|
package/dist/index.js
CHANGED
|
@@ -1,32 +1,63 @@
|
|
|
1
1
|
import { markdownConfigDefaults } from "@astrojs/markdown-remark";
|
|
2
2
|
import { toRemarkInitializeAstroData } from "@astrojs/markdown-remark/dist/internal.js";
|
|
3
3
|
import { compile as mdxCompile } from "@mdx-js/mdx";
|
|
4
|
-
import mdxPlugin from "@mdx-js/rollup";
|
|
5
4
|
import { parse as parseESM } from "es-module-lexer";
|
|
6
5
|
import fs from "node:fs/promises";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { SourceMapGenerator } from "source-map";
|
|
7
8
|
import { VFile } from "vfile";
|
|
8
9
|
import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from "./plugins.js";
|
|
9
|
-
import { getFileInfo, parseFrontmatter } from "./utils.js";
|
|
10
|
-
|
|
11
|
-
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";
|
|
10
|
+
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from "./utils.js";
|
|
11
|
+
import astroJSXRenderer from "astro/jsx/renderer.js";
|
|
12
12
|
function mdx(partialMdxOptions = {}) {
|
|
13
13
|
return {
|
|
14
14
|
name: "@astrojs/mdx",
|
|
15
15
|
hooks: {
|
|
16
|
-
"astro:config:setup": async (
|
|
16
|
+
"astro:config:setup": async (params) => {
|
|
17
|
+
const {
|
|
18
|
+
updateConfig,
|
|
19
|
+
config,
|
|
20
|
+
addPageExtension,
|
|
21
|
+
addContentEntryType,
|
|
22
|
+
command,
|
|
23
|
+
addRenderer
|
|
24
|
+
} = params;
|
|
25
|
+
addRenderer(astroJSXRenderer);
|
|
17
26
|
addPageExtension(".mdx");
|
|
18
|
-
|
|
27
|
+
addContentEntryType({
|
|
28
|
+
extensions: [".mdx"],
|
|
29
|
+
async getEntryInfo({ fileUrl, contents }) {
|
|
30
|
+
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
|
|
31
|
+
return {
|
|
32
|
+
data: parsed.data,
|
|
33
|
+
body: parsed.content,
|
|
34
|
+
slug: parsed.data.slug,
|
|
35
|
+
rawData: parsed.matter
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
contentModuleTypes: await fs.readFile(
|
|
39
|
+
new URL("../template/content-module-types.d.ts", import.meta.url),
|
|
40
|
+
"utf-8"
|
|
41
|
+
),
|
|
42
|
+
// MDX can import scripts and styles,
|
|
43
|
+
// so wrap all MDX files with script / style propagation checks
|
|
44
|
+
handlePropagation: true
|
|
45
|
+
});
|
|
46
|
+
const extendMarkdownConfig = partialMdxOptions.extendMarkdownConfig ?? defaultMdxOptions.extendMarkdownConfig;
|
|
19
47
|
const mdxOptions = applyDefaultOptions({
|
|
20
48
|
options: partialMdxOptions,
|
|
21
|
-
defaults:
|
|
49
|
+
defaults: markdownConfigToMdxOptions(
|
|
50
|
+
extendMarkdownConfig ? config.markdown : markdownConfigDefaults
|
|
51
|
+
)
|
|
22
52
|
});
|
|
23
53
|
const mdxPluginOpts = {
|
|
24
|
-
remarkPlugins: await getRemarkPlugins(mdxOptions
|
|
54
|
+
remarkPlugins: await getRemarkPlugins(mdxOptions),
|
|
25
55
|
rehypePlugins: getRehypePlugins(mdxOptions),
|
|
26
56
|
recmaPlugins: mdxOptions.recmaPlugins,
|
|
27
57
|
remarkRehypeOptions: mdxOptions.remarkRehype,
|
|
28
58
|
jsx: true,
|
|
29
59
|
jsxImportSource: "astro",
|
|
60
|
+
// Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
|
|
30
61
|
format: "mdx",
|
|
31
62
|
mdExtensions: []
|
|
32
63
|
};
|
|
@@ -37,27 +68,43 @@ function mdx(partialMdxOptions = {}) {
|
|
|
37
68
|
vite: {
|
|
38
69
|
plugins: [
|
|
39
70
|
{
|
|
71
|
+
name: "@mdx-js/rollup",
|
|
40
72
|
enforce: "pre",
|
|
41
|
-
...mdxPlugin(mdxPluginOpts),
|
|
42
73
|
configResolved(resolved) {
|
|
43
74
|
importMetaEnv = { ...importMetaEnv, ...resolved.env };
|
|
75
|
+
const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === "astro:jsx");
|
|
76
|
+
if (jsxPluginIndex !== -1) {
|
|
77
|
+
const myPluginIndex = resolved.plugins.findIndex(
|
|
78
|
+
(p) => p.name === "@mdx-js/rollup"
|
|
79
|
+
);
|
|
80
|
+
if (myPluginIndex !== -1) {
|
|
81
|
+
const myPlugin = resolved.plugins[myPluginIndex];
|
|
82
|
+
resolved.plugins.splice(myPluginIndex, 1);
|
|
83
|
+
resolved.plugins.splice(jsxPluginIndex, 0, myPlugin);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
44
86
|
},
|
|
87
|
+
// Override transform to alter code before MDX compilation
|
|
88
|
+
// ex. inject layouts
|
|
45
89
|
async transform(_, id) {
|
|
46
|
-
if (!id.endsWith("mdx"))
|
|
90
|
+
if (!id.endsWith(".mdx"))
|
|
47
91
|
return;
|
|
48
92
|
const { fileId } = getFileInfo(id, config);
|
|
49
93
|
const code = await fs.readFile(fileId, "utf-8");
|
|
50
94
|
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
51
95
|
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
|
52
96
|
...mdxPluginOpts,
|
|
97
|
+
elementAttributeNameCase: "html",
|
|
53
98
|
remarkPlugins: [
|
|
99
|
+
// Ensure `data.astro` is available to all remark plugins
|
|
54
100
|
toRemarkInitializeAstroData({ userFrontmatter: frontmatter }),
|
|
55
101
|
...mdxPluginOpts.remarkPlugins ?? []
|
|
56
102
|
],
|
|
57
103
|
recmaPlugins: [
|
|
58
104
|
...mdxPluginOpts.recmaPlugins ?? [],
|
|
59
105
|
() => recmaInjectImportMetaEnvPlugin({ importMetaEnv })
|
|
60
|
-
]
|
|
106
|
+
],
|
|
107
|
+
SourceMapGenerator: config.vite.build?.sourcemap ? SourceMapGenerator : void 0
|
|
61
108
|
});
|
|
62
109
|
return {
|
|
63
110
|
code: escapeViteEnvReferences(String(compiled.value)),
|
|
@@ -67,6 +114,7 @@ function mdx(partialMdxOptions = {}) {
|
|
|
67
114
|
},
|
|
68
115
|
{
|
|
69
116
|
name: "@astrojs/mdx-postprocess",
|
|
117
|
+
// These transforms must happen *after* JSX runtime transformations
|
|
70
118
|
transform(code, id) {
|
|
71
119
|
if (!id.endsWith(".mdx"))
|
|
72
120
|
return;
|
|
@@ -79,44 +127,37 @@ function mdx(partialMdxOptions = {}) {
|
|
|
79
127
|
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
80
128
|
}
|
|
81
129
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
82
|
-
if (!moduleExports.
|
|
130
|
+
if (!moduleExports.find(({ n }) => n === "url")) {
|
|
83
131
|
code += `
|
|
84
132
|
export const url = ${JSON.stringify(fileUrl)};`;
|
|
85
133
|
}
|
|
86
|
-
if (!moduleExports.
|
|
134
|
+
if (!moduleExports.find(({ n }) => n === "file")) {
|
|
87
135
|
code += `
|
|
88
136
|
export const file = ${JSON.stringify(fileId)};`;
|
|
89
137
|
}
|
|
90
|
-
if (!moduleExports.
|
|
91
|
-
|
|
92
|
-
export function rawContent() { throw new Error(${JSON.stringify(
|
|
93
|
-
RAW_CONTENT_ERROR
|
|
94
|
-
)}) };`;
|
|
95
|
-
}
|
|
96
|
-
if (!moduleExports.includes("compiledContent")) {
|
|
97
|
-
code += `
|
|
98
|
-
export function compiledContent() { throw new Error(${JSON.stringify(
|
|
99
|
-
COMPILED_CONTENT_ERROR
|
|
100
|
-
)}) };`;
|
|
101
|
-
}
|
|
102
|
-
if (!moduleExports.includes("Content")) {
|
|
138
|
+
if (!moduleExports.find(({ n }) => n === "Content")) {
|
|
139
|
+
const hasComponents = moduleExports.find(({ n }) => n === "components");
|
|
103
140
|
code = code.replace("export default MDXContent;", "");
|
|
104
141
|
code += `
|
|
105
142
|
export const Content = (props = {}) => MDXContent({
|
|
106
143
|
...props,
|
|
107
|
-
components: { Fragment, ...props.components },
|
|
144
|
+
components: { Fragment${hasComponents ? ", ...components" : ""}, ...props.components },
|
|
108
145
|
});
|
|
109
146
|
export default Content;`;
|
|
110
147
|
}
|
|
111
148
|
code += `
|
|
149
|
+
Content[Symbol.for('mdx-component')] = true`;
|
|
150
|
+
code += `
|
|
112
151
|
Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
152
|
+
code += `
|
|
153
|
+
Content.moduleId = ${JSON.stringify(id)};`;
|
|
113
154
|
if (command === "dev") {
|
|
114
155
|
code += `
|
|
115
156
|
if (import.meta.hot) {
|
|
116
157
|
import.meta.hot.decline();
|
|
117
158
|
}`;
|
|
118
159
|
}
|
|
119
|
-
return escapeViteEnvReferences(code);
|
|
160
|
+
return { code: escapeViteEnvReferences(code), map: null };
|
|
120
161
|
}
|
|
121
162
|
}
|
|
122
163
|
]
|
|
@@ -126,14 +167,20 @@ if (import.meta.hot) {
|
|
|
126
167
|
}
|
|
127
168
|
};
|
|
128
169
|
}
|
|
129
|
-
const
|
|
130
|
-
...markdownConfigDefaults,
|
|
170
|
+
const defaultMdxOptions = {
|
|
131
171
|
extendMarkdownConfig: true,
|
|
132
|
-
recmaPlugins: []
|
|
133
|
-
remarkPlugins: [],
|
|
134
|
-
rehypePlugins: [],
|
|
135
|
-
remarkRehype: {}
|
|
172
|
+
recmaPlugins: []
|
|
136
173
|
};
|
|
174
|
+
function markdownConfigToMdxOptions(markdownConfig) {
|
|
175
|
+
return {
|
|
176
|
+
...defaultMdxOptions,
|
|
177
|
+
...markdownConfig,
|
|
178
|
+
remarkPlugins: ignoreStringPlugins(markdownConfig.remarkPlugins),
|
|
179
|
+
rehypePlugins: ignoreStringPlugins(markdownConfig.rehypePlugins),
|
|
180
|
+
remarkRehype: markdownConfig.remarkRehype ?? {},
|
|
181
|
+
optimize: false
|
|
182
|
+
};
|
|
183
|
+
}
|
|
137
184
|
function applyDefaultOptions({
|
|
138
185
|
options,
|
|
139
186
|
defaults
|
|
@@ -147,7 +194,8 @@ function applyDefaultOptions({
|
|
|
147
194
|
smartypants: options.smartypants ?? defaults.smartypants,
|
|
148
195
|
remarkPlugins: options.remarkPlugins ?? defaults.remarkPlugins,
|
|
149
196
|
rehypePlugins: options.rehypePlugins ?? defaults.rehypePlugins,
|
|
150
|
-
shikiConfig: options.shikiConfig ?? defaults.shikiConfig
|
|
197
|
+
shikiConfig: options.shikiConfig ?? defaults.shikiConfig,
|
|
198
|
+
optimize: options.optimize ?? defaults.optimize
|
|
151
199
|
};
|
|
152
200
|
}
|
|
153
201
|
function escapeViteEnvReferences(code) {
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { AstroConfig } from 'astro';
|
|
1
|
+
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
|
3
2
|
import type { VFile } from 'vfile';
|
|
4
|
-
import { MdxOptions } from './index.js';
|
|
3
|
+
import type { MdxOptions } from './index.js';
|
|
5
4
|
export declare function recmaInjectImportMetaEnvPlugin({ importMetaEnv, }: {
|
|
6
5
|
importMetaEnv: Record<string, any>;
|
|
7
6
|
}): (tree: any) => void;
|
|
8
7
|
export declare function rehypeApplyFrontmatterExport(): (tree: any, vfile: VFile) => void;
|
|
9
|
-
export declare function getRemarkPlugins(mdxOptions: MdxOptions
|
|
10
|
-
export declare function getRehypePlugins(mdxOptions: MdxOptions):
|
|
8
|
+
export declare function getRemarkPlugins(mdxOptions: MdxOptions): Promise<PluggableList>;
|
|
9
|
+
export declare function getRehypePlugins(mdxOptions: MdxOptions): PluggableList;
|
package/dist/plugins.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { rehypeHeadingIds } from "@astrojs/markdown-remark";
|
|
1
|
+
import { rehypeHeadingIds, remarkCollectImages } from "@astrojs/markdown-remark";
|
|
2
2
|
import {
|
|
3
3
|
InvalidAstroDataError,
|
|
4
4
|
safelyGetAstroData
|
|
5
5
|
} from "@astrojs/markdown-remark/dist/internal.js";
|
|
6
6
|
import { nodeTypes } from "@mdx-js/mdx";
|
|
7
7
|
import { visit as estreeVisit } from "estree-util-visit";
|
|
8
|
-
import { bold, yellow } from "kleur/colors";
|
|
9
|
-
import { pathToFileURL } from "node:url";
|
|
10
8
|
import rehypeRaw from "rehype-raw";
|
|
11
9
|
import remarkGfm from "remark-gfm";
|
|
12
10
|
import remarkSmartypants from "remark-smartypants";
|
|
13
|
-
import { visit } from "unist-util-visit";
|
|
14
11
|
import { rehypeInjectHeadingsExport } from "./rehype-collect-headings.js";
|
|
15
12
|
import rehypeMetaString from "./rehype-meta-string.js";
|
|
13
|
+
import { rehypeOptimizeStatic } from "./rehype-optimize-static.js";
|
|
14
|
+
import { remarkImageToComponent } from "./remark-images-to-component.js";
|
|
16
15
|
import remarkPrism from "./remark-prism.js";
|
|
17
16
|
import remarkShiki from "./remark-shiki.js";
|
|
18
|
-
import {
|
|
17
|
+
import { jsToTreeNode } from "./utils.js";
|
|
18
|
+
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
|
|
19
19
|
function recmaInjectImportMetaEnvPlugin({
|
|
20
20
|
importMetaEnv
|
|
21
21
|
}) {
|
|
@@ -43,6 +43,8 @@ function rehypeApplyFrontmatterExport() {
|
|
|
43
43
|
const astroData = safelyGetAstroData(vfile.data);
|
|
44
44
|
if (astroData instanceof InvalidAstroDataError)
|
|
45
45
|
throw new Error(
|
|
46
|
+
// Copied from Astro core `errors-data`
|
|
47
|
+
// TODO: find way to import error data from core
|
|
46
48
|
'[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.'
|
|
47
49
|
);
|
|
48
50
|
const { frontmatter } = astroData;
|
|
@@ -52,6 +54,7 @@ function rehypeApplyFrontmatterExport() {
|
|
|
52
54
|
if (frontmatter.layout) {
|
|
53
55
|
exportNodes.unshift(
|
|
54
56
|
jsToTreeNode(
|
|
57
|
+
/** @see 'vite-plugin-markdown' for layout props reference */
|
|
55
58
|
`import { jsx as layoutJsx } from 'astro/jsx-runtime';
|
|
56
59
|
|
|
57
60
|
export default async function ({ children }) {
|
|
@@ -59,22 +62,6 @@ function rehypeApplyFrontmatterExport() {
|
|
|
59
62
|
const { layout, ...content } = frontmatter;
|
|
60
63
|
content.file = file;
|
|
61
64
|
content.url = url;
|
|
62
|
-
content.astro = {};
|
|
63
|
-
Object.defineProperty(content.astro, 'headings', {
|
|
64
|
-
get() {
|
|
65
|
-
throw new Error('The "astro" property is no longer supported! To access "headings" from your layout, try using "Astro.props.headings."')
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
Object.defineProperty(content.astro, 'html', {
|
|
69
|
-
get() {
|
|
70
|
-
throw new Error('The "astro" property is no longer supported! To access "html" from your layout, try using "Astro.props.compiledContent()."')
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
Object.defineProperty(content.astro, 'source', {
|
|
74
|
-
get() {
|
|
75
|
-
throw new Error('The "astro" property is no longer supported! To access "source" from your layout, try using "Astro.props.rawContent()."')
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
65
|
return layoutJsx(Layout, {
|
|
79
66
|
file,
|
|
80
67
|
url,
|
|
@@ -91,79 +78,48 @@ function rehypeApplyFrontmatterExport() {
|
|
|
91
78
|
tree.children = exportNodes.concat(tree.children);
|
|
92
79
|
};
|
|
93
80
|
}
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (isRelativePath(node.url)) {
|
|
104
|
-
relImagePaths.add(node.url);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
if (relImagePaths.size === 0)
|
|
108
|
-
return;
|
|
109
|
-
const errorMessage = `Relative image paths are not supported in the content/ directory. Place local images in the public/ directory and use absolute paths (see https://docs.astro.build/en/guides/images/#in-markdown-files):
|
|
110
|
-
` + [...relImagePaths].map((path) => JSON.stringify(path)).join(",\n");
|
|
111
|
-
throw new Error(errorMessage);
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
async function getRemarkPlugins(mdxOptions, config) {
|
|
116
|
-
let remarkPlugins = [];
|
|
117
|
-
if (mdxOptions.syntaxHighlight === "shiki") {
|
|
118
|
-
remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
|
|
119
|
-
}
|
|
120
|
-
if (mdxOptions.syntaxHighlight === "prism") {
|
|
121
|
-
remarkPlugins.push(remarkPrism);
|
|
122
|
-
}
|
|
123
|
-
if (mdxOptions.gfm) {
|
|
124
|
-
remarkPlugins.push(remarkGfm);
|
|
81
|
+
async function getRemarkPlugins(mdxOptions) {
|
|
82
|
+
let remarkPlugins = [remarkCollectImages, remarkImageToComponent];
|
|
83
|
+
if (!isPerformanceBenchmark) {
|
|
84
|
+
if (mdxOptions.gfm) {
|
|
85
|
+
remarkPlugins.push(remarkGfm);
|
|
86
|
+
}
|
|
87
|
+
if (mdxOptions.smartypants) {
|
|
88
|
+
remarkPlugins.push(remarkSmartypants);
|
|
89
|
+
}
|
|
125
90
|
}
|
|
126
|
-
|
|
127
|
-
|
|
91
|
+
remarkPlugins = [...remarkPlugins, ...mdxOptions.remarkPlugins];
|
|
92
|
+
if (!isPerformanceBenchmark) {
|
|
93
|
+
if (mdxOptions.syntaxHighlight === "shiki") {
|
|
94
|
+
remarkPlugins.push([await remarkShiki(mdxOptions.shikiConfig)]);
|
|
95
|
+
}
|
|
96
|
+
if (mdxOptions.syntaxHighlight === "prism") {
|
|
97
|
+
remarkPlugins.push(remarkPrism);
|
|
98
|
+
}
|
|
128
99
|
}
|
|
129
|
-
remarkPlugins = [...remarkPlugins, ...ignoreStringPlugins(mdxOptions.remarkPlugins)];
|
|
130
|
-
remarkPlugins.push(toRemarkContentRelImageError(config));
|
|
131
100
|
return remarkPlugins;
|
|
132
101
|
}
|
|
133
102
|
function getRehypePlugins(mdxOptions) {
|
|
134
103
|
let rehypePlugins = [
|
|
104
|
+
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
|
|
135
105
|
rehypeMetaString,
|
|
106
|
+
// rehypeRaw allows custom syntax highlighters to work without added config
|
|
136
107
|
[rehypeRaw, { passThrough: nodeTypes }]
|
|
137
108
|
];
|
|
138
109
|
rehypePlugins = [
|
|
139
110
|
...rehypePlugins,
|
|
140
|
-
...
|
|
141
|
-
|
|
142
|
-
|
|
111
|
+
...mdxOptions.rehypePlugins,
|
|
112
|
+
// getHeadings() is guaranteed by TS, so this must be included.
|
|
113
|
+
// We run `rehypeHeadingIds` _last_ to respect any custom IDs set by user plugins.
|
|
114
|
+
...isPerformanceBenchmark ? [] : [rehypeHeadingIds, rehypeInjectHeadingsExport],
|
|
115
|
+
// computed from `astro.data.frontmatter` in VFile data
|
|
143
116
|
rehypeApplyFrontmatterExport
|
|
144
117
|
];
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
let validPlugins = [];
|
|
149
|
-
let hasInvalidPlugin = false;
|
|
150
|
-
for (const plugin of plugins) {
|
|
151
|
-
if (typeof plugin === "string") {
|
|
152
|
-
console.warn(yellow(`[MDX] ${bold(plugin)} not applied.`));
|
|
153
|
-
hasInvalidPlugin = true;
|
|
154
|
-
} else if (Array.isArray(plugin) && typeof plugin[0] === "string") {
|
|
155
|
-
console.warn(yellow(`[MDX] ${bold(plugin[0])} not applied.`));
|
|
156
|
-
hasInvalidPlugin = true;
|
|
157
|
-
} else {
|
|
158
|
-
validPlugins.push(plugin);
|
|
159
|
-
}
|
|
118
|
+
if (mdxOptions.optimize) {
|
|
119
|
+
const options = mdxOptions.optimize === true ? void 0 : mdxOptions.optimize;
|
|
120
|
+
rehypePlugins.push([rehypeOptimizeStatic, options]);
|
|
160
121
|
}
|
|
161
|
-
|
|
162
|
-
console.warn(
|
|
163
|
-
`To inherit Markdown plugins in MDX, please use explicit imports in your config instead of "strings." See Markdown docs: https://docs.astro.build/en/guides/markdown-content/#markdown-plugins`
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
return validPlugins;
|
|
122
|
+
return rehypePlugins;
|
|
167
123
|
}
|
|
168
124
|
function getImportMetaEnvVariableName(node) {
|
|
169
125
|
try {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { MarkdownVFile } from '@astrojs/markdown-remark';
|
|
1
|
+
import type { MarkdownVFile } from '@astrojs/markdown-remark';
|
|
2
2
|
export declare function rehypeInjectHeadingsExport(): (tree: any, file: MarkdownVFile) => void;
|
|
@@ -2,9 +2,8 @@ import { visit } from "unist-util-visit";
|
|
|
2
2
|
function rehypeMetaString() {
|
|
3
3
|
return function(tree) {
|
|
4
4
|
visit(tree, (node) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
node.properties ?? (node.properties = {});
|
|
5
|
+
if (node.type === "element" && node.tagName === "code" && node.data?.meta) {
|
|
6
|
+
node.properties ??= {};
|
|
8
7
|
node.properties.metastring = node.data.meta;
|
|
9
8
|
}
|
|
10
9
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface OptimizeOptions {
|
|
2
|
+
customComponentNames?: string[];
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* For MDX only, collapse static subtrees of the hast into `set:html`. Subtrees
|
|
6
|
+
* do not include any MDX elements.
|
|
7
|
+
*
|
|
8
|
+
* This optimization reduces the JS output as more content are represented as a
|
|
9
|
+
* string instead, which also reduces the AST size that Rollup holds in memory.
|
|
10
|
+
*/
|
|
11
|
+
export declare function rehypeOptimizeStatic(options?: OptimizeOptions): (tree: any) => void;
|