@astrojs/mdx 0.12.0 → 0.12.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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +14 -0
- package/README.md +60 -401
- package/dist/index.js +16 -4
- package/package.json +2 -2
- package/src/index.ts +23 -6
- package/test/fixtures/mdx-component/src/components/WithFragment.mdx +3 -0
- package/test/fixtures/mdx-component/src/pages/glob.astro +11 -2
- package/test/fixtures/mdx-component/src/pages/w-fragment.astro +5 -0
- package/test/fixtures/mdx-slots/src/components/Slotted.astro +4 -0
- package/test/fixtures/mdx-slots/src/components/Test.mdx +15 -0
- package/test/fixtures/mdx-slots/src/pages/glob.astro +11 -0
- package/test/fixtures/mdx-slots/src/pages/index.astro +5 -0
- package/test/mdx-component.test.js +79 -0
- package/test/mdx-slots.js +124 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[34m@astrojs/mdx:build: [0mcache hit, replaying output [2m7b0a39f7d517504d[0m
|
|
2
|
+
[34m@astrojs/mdx:build: [0m
|
|
3
|
+
[34m@astrojs/mdx:build: [0m> @astrojs/mdx@0.12.2 build /home/runner/work/astro/astro/packages/integrations/mdx
|
|
4
|
+
[34m@astrojs/mdx:build: [0m> astro-scripts build "src/**/*.ts" && tsc
|
|
5
|
+
[34m@astrojs/mdx:build: [0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @astrojs/mdx
|
|
2
2
|
|
|
3
|
+
## 0.12.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#5586](https://github.com/withastro/astro/pull/5586) [`f4ff69a3c`](https://github.com/withastro/astro/commit/f4ff69a3cd874c8804c6d01c7cbbaed8a8e90be7) Thanks [@delucis](https://github.com/delucis)! - Fix link in MDX integration README
|
|
8
|
+
|
|
9
|
+
- [#5570](https://github.com/withastro/astro/pull/5570) [`3f811eb68`](https://github.com/withastro/astro/commit/3f811eb682d55bd1f908f9b4bc3b795d2859d713) Thanks [@sarah11918](https://github.com/sarah11918)! - Revise README
|
|
10
|
+
|
|
11
|
+
## 0.12.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#5522](https://github.com/withastro/astro/pull/5522) [`efc4363e0`](https://github.com/withastro/astro/commit/efc4363e0baf7f92900e20af339811bb3df42b0e) Thanks [@delucis](https://github.com/delucis)! - Support use of `<Fragment>` in MDX files rendered with `<Content />` component
|
|
16
|
+
|
|
3
17
|
## 0.12.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -13,10 +13,7 @@ This **[Astro integration][astro-integration]** enables the usage of [MDX](https
|
|
|
13
13
|
|
|
14
14
|
## Why MDX?
|
|
15
15
|
|
|
16
|
-
MDX
|
|
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.
|
|
16
|
+
MDX allows you to [use variables, JSX expressions and components within Markdown content](https://docs.astro.build/en/guides/markdown-content/#mdx-only-features) in Astro. If you have existing content authored in MDX, this integration allows you to bring those files to your Astro project.
|
|
20
17
|
|
|
21
18
|
## Installation
|
|
22
19
|
|
|
@@ -45,7 +42,7 @@ npm install @astrojs/mdx
|
|
|
45
42
|
|
|
46
43
|
Then, apply this integration to your `astro.config.*` file using the `integrations` property:
|
|
47
44
|
|
|
48
|
-
|
|
45
|
+
**`astro.config.mjs`**
|
|
49
46
|
|
|
50
47
|
```js
|
|
51
48
|
import { defineConfig } from 'astro/config';
|
|
@@ -57,8 +54,6 @@ export default defineConfig({
|
|
|
57
54
|
});
|
|
58
55
|
```
|
|
59
56
|
|
|
60
|
-
Finally, restart the dev server.
|
|
61
|
-
|
|
62
57
|
### Editor Integration
|
|
63
58
|
|
|
64
59
|
[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.
|
|
@@ -71,476 +66,139 @@ Finally, restart the dev server.
|
|
|
71
66
|
|
|
72
67
|
## Usage
|
|
73
68
|
|
|
74
|
-
|
|
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
|
-
|
|
80
|
-
- 📦 how framework components are loaded,
|
|
81
|
-
- 💧 client-side hydration options, and
|
|
82
|
-
- 🤝 opportunities to mix and nest frameworks together
|
|
83
|
-
|
|
84
|
-
[**Client Directives**](https://docs.astro.build/en/reference/directives-reference/#client-directives) are still required in `.mdx` files.
|
|
85
|
-
|
|
86
|
-
> **Note**: `.mdx` files adhere to strict JSX syntax rather than Astro's HTML-like syntax.
|
|
87
|
-
|
|
88
|
-
### Variables
|
|
89
|
-
|
|
90
|
-
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.
|
|
91
|
-
|
|
92
|
-
For instance, you can export a `title` field from an MDX page or component to use as a heading with `{JSX expressions}`:
|
|
93
|
-
|
|
94
|
-
```mdx
|
|
95
|
-
export const title = 'My first MDX post'
|
|
96
|
-
|
|
97
|
-
# {title}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
This `title` will be accessible from `import` and [glob](https://docs.astro.build/en/reference/api-reference/#astroglob) statements as well:
|
|
101
|
-
|
|
102
|
-
```astro
|
|
103
|
-
---
|
|
104
|
-
// src/pages/index.astro
|
|
105
|
-
const posts = await Astro.glob('./*.mdx');
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
{posts.map(post => <p>{post.title}</p>)}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
See [the official "how MDX works" guide](https://mdxjs.com/docs/using-mdx/#how-mdx-works) for more on MDX variables.
|
|
112
|
-
|
|
113
|
-
### Exported properties
|
|
114
|
-
|
|
115
|
-
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).
|
|
116
|
-
|
|
117
|
-
#### `file`
|
|
118
|
-
|
|
119
|
-
The absolute path to the MDX file (e.g. `home/user/projects/.../file.md`).
|
|
120
|
-
|
|
121
|
-
#### `url`
|
|
122
|
-
|
|
123
|
-
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`.
|
|
124
|
-
|
|
125
|
-
#### `getHeadings()`
|
|
126
|
-
|
|
127
|
-
**Returns:** `{ depth: number; slug: string; text: string }[]`
|
|
128
|
-
|
|
129
|
-
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.
|
|
130
|
-
|
|
131
|
-
### Frontmatter
|
|
132
|
-
|
|
133
|
-
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.
|
|
134
|
-
|
|
135
|
-
For example, we can add a `title` and `publishDate` to an MDX page or component like so:
|
|
136
|
-
|
|
137
|
-
```mdx
|
|
138
|
-
---
|
|
139
|
-
title: 'My first MDX post'
|
|
140
|
-
publishDate: '21 September 2022'
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
# {frontmatter.title}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
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!
|
|
147
|
-
|
|
148
|
-
```astro
|
|
149
|
-
---
|
|
150
|
-
// src/pages/index.astro
|
|
151
|
-
const posts = await Astro.glob('./*.mdx');
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
{posts.map(post => (
|
|
155
|
-
<Fragment>
|
|
156
|
-
<h2>{post.frontmatter.title}</h2>
|
|
157
|
-
<time>{post.frontmatter.publishDate}</time>
|
|
158
|
-
</Fragment>
|
|
159
|
-
))}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Inject frontmatter via remark or rehype plugins
|
|
163
|
-
|
|
164
|
-
You may want to inject frontmatter properties across all of your MDX files. By using a [remark](#remarkplugins) or [rehype](#rehypeplugins) plugin, you can generate these properties based on a file’s contents.
|
|
165
|
-
|
|
166
|
-
You can append to the `data.astro.frontmatter` property from your plugin’s `file` argument like so:
|
|
167
|
-
|
|
168
|
-
```js
|
|
169
|
-
// example-remark-plugin.mjs
|
|
170
|
-
export function exampleRemarkPlugin() {
|
|
171
|
-
// All remark and rehype plugins return a separate function
|
|
172
|
-
return function (tree, file) {
|
|
173
|
-
file.data.astro.frontmatter.customProperty = 'Generated property';
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
After applying this plugin to your MDX integration config:
|
|
179
|
-
|
|
180
|
-
```js
|
|
181
|
-
// astro.config.mjs
|
|
182
|
-
import mdx from '@astrojs/mdx';
|
|
183
|
-
import { exampleRemarkPlugin } from './example-remark-plugin.mjs';
|
|
184
|
-
|
|
185
|
-
export default {
|
|
186
|
-
integrations: [
|
|
187
|
-
mdx({
|
|
188
|
-
remarkPlugins: [exampleRemarkPlugin],
|
|
189
|
-
}),
|
|
190
|
-
],
|
|
191
|
-
};
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
…every MDX file will have `customProperty` in its frontmatter! See [our Markdown documentation](https://docs.astro.build/en/guides/markdown-content/#example-injecting-frontmatter) for more usage instructions and a [reading time plugin example](https://docs.astro.build/en/guides/markdown-content/#example-calculate-reading-time).
|
|
195
|
-
|
|
196
|
-
### Layouts
|
|
197
|
-
Layouts can be applied [in the same way as standard Astro Markdown](https://docs.astro.build/en/guides/markdown-content/#frontmatter-layout). 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
|
-
|
|
264
|
-
- Heading information (i.e. `h1 -> h6` elements) is available via the `headings` array, rather than a `getHeadings()` function.
|
|
265
|
-
- `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.
|
|
266
|
-
|
|
267
|
-
Astro recommends using the `MDXLayoutProps` type (see previous section) to explore all available properties.
|
|
268
|
-
|
|
269
|
-
#### Importing layouts manually
|
|
270
|
-
|
|
271
|
-
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:
|
|
272
|
-
|
|
273
|
-
```mdx
|
|
274
|
-
---
|
|
275
|
-
// src/pages/posts/first-post.mdx
|
|
276
|
-
|
|
277
|
-
title: 'My first MDX post'
|
|
278
|
-
publishDate: '21 September 2022'
|
|
279
|
-
---
|
|
280
|
-
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
281
|
-
|
|
282
|
-
function fancyJsHelper() {
|
|
283
|
-
return "Try doing that with YAML!";
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
<BaseLayout title={frontmatter.title} fancyJsHelper={fancyJsHelper}>
|
|
287
|
-
Welcome to my new Astro blog, using MDX!
|
|
288
|
-
</BaseLayout>
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
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:
|
|
292
|
-
|
|
293
|
-
```astro
|
|
294
|
-
---
|
|
295
|
-
// src/layouts/BaseLayout.astro
|
|
296
|
-
const { title, fancyJsHelper } = Astro.props;
|
|
297
|
-
---
|
|
298
|
-
<!-- -->
|
|
299
|
-
<h1>{title}</h1>
|
|
300
|
-
<slot />
|
|
301
|
-
<p>{fancyJsHelper()}</p>
|
|
302
|
-
<!-- -->
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Custom components
|
|
306
|
-
|
|
307
|
-
Under the hood, MDX will convert Markdown into HTML components. For example, this blockquote:
|
|
308
|
-
|
|
309
|
-
```md
|
|
310
|
-
> A blockquote with *some* emphasis.
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
will be converted into this HTML:
|
|
314
|
-
|
|
315
|
-
```html
|
|
316
|
-
<blockquote>
|
|
317
|
-
<p>A blockquote with <em>some</em> emphasis.</p>
|
|
318
|
-
</blockquote>
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
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.
|
|
322
|
-
|
|
323
|
-
```astro title="src/components/Blockquote.astro"
|
|
324
|
-
---
|
|
325
|
-
const props = Astro.props;
|
|
326
|
-
---
|
|
69
|
+
With the Astro MDX integration, you can [add MDX pages to your project](/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.
|
|
327
70
|
|
|
328
|
-
|
|
329
|
-
<span class="text-4xl text-blue-600 mb-2">“</span>
|
|
330
|
-
<slot />
|
|
331
|
-
</blockquote>
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
Then in the MDX file you import the component and export it to the `components` export.
|
|
335
|
-
|
|
336
|
-
```mdx title="src/pages/posts/post-1.mdx" {2}
|
|
337
|
-
import Blockquote from '../components/Blockquote.astro';
|
|
338
|
-
export const components = { blockquote: Blockquote };
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
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.
|
|
71
|
+
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).
|
|
342
72
|
|
|
343
|
-
|
|
73
|
+
See how MDX works in Astro with examples in our [Markdown & MDX guide](https://docs.astro.build/en/guides/markdown-content/).
|
|
344
74
|
|
|
345
|
-
|
|
75
|
+
Visit the [MDX docs](https://mdxjs.com/docs/what-is-mdx/) to learn about using standard MDX features.
|
|
346
76
|
|
|
347
|
-
|
|
77
|
+
## Configuration
|
|
348
78
|
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
import { Content, components } from '../content.mdx';
|
|
352
|
-
import Heading from '../Heading.astro';
|
|
353
|
-
---
|
|
79
|
+
Once the MDX integration is installed, no configuration is necessary to use `.mdx` files in your Astro project.
|
|
354
80
|
|
|
355
|
-
|
|
356
|
-
```
|
|
81
|
+
You can extend how your MDX is rendered by adding remark, rehype and recma plugins.
|
|
357
82
|
|
|
358
|
-
|
|
83
|
+
- [`extendPlugins`](#extendplugins)
|
|
84
|
+
- [`remarkRehype`](#remarkrehype)
|
|
85
|
+
- [`remarkPlugins`](#remarkplugins)
|
|
86
|
+
- [`rehypePlugins`](#rehypeplugins)
|
|
87
|
+
- [`recmaPlugins`](#recmaplugins)
|
|
359
88
|
|
|
360
|
-
|
|
89
|
+
### `extendPlugins`
|
|
361
90
|
|
|
362
|
-
|
|
91
|
+
You can customize how MDX files inherit your project’s existing Markdown configuration using the `extendPlugins` option.
|
|
363
92
|
|
|
364
|
-
|
|
365
|
-
// astro.config.mjs
|
|
366
|
-
export default {
|
|
367
|
-
markdown: {
|
|
368
|
-
shikiConfig: {
|
|
369
|
-
theme: 'dracula',
|
|
370
|
-
},
|
|
371
|
-
},
|
|
372
|
-
integrations: [mdx()],
|
|
373
|
-
}
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
Visit [our Shiki configuration docs](https://docs.astro.build/en/guides/markdown-content/#shiki-configuration) for more on using Shiki with Astro.
|
|
377
|
-
|
|
378
|
-
#### Switch to Prism
|
|
93
|
+
#### `markdown` (default)
|
|
379
94
|
|
|
380
|
-
|
|
95
|
+
Astro's MDX files will inherit all [`markdown` options](https://docs.astro.build/en/reference/configuration-reference/#markdown-options) in your Astro configuration file, which includes the [GitHub-Flavored Markdown](https://github.com/remarkjs/remark-gfm) and [Smartypants](https://github.com/silvenon/remark-smartypants) plugins by default.
|
|
381
96
|
|
|
382
|
-
|
|
383
|
-
// astro.config.mjs
|
|
384
|
-
export default {
|
|
385
|
-
markdown: {
|
|
386
|
-
syntaxHighlight: 'prism',
|
|
387
|
-
},
|
|
388
|
-
integrations: [mdx()],
|
|
389
|
-
}
|
|
390
|
-
```
|
|
97
|
+
Any additional plugins you apply in your MDX config will be applied *after* your configured Markdown plugins.
|
|
391
98
|
|
|
392
|
-
|
|
99
|
+
#### `astroDefaults`
|
|
393
100
|
|
|
394
|
-
|
|
101
|
+
Astro's MDX files will apply only [Astro's default plugins](/en/reference/configuration-reference/#markdownextenddefaultplugins), without inheriting the rest of your Markdown config.
|
|
395
102
|
|
|
396
|
-
|
|
103
|
+
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) to your MDX files, while ignoring any `markdown.remarkPlugins` configuration:
|
|
397
104
|
|
|
398
|
-
```js
|
|
105
|
+
```js "extendPlugins: 'astroDefaults'"
|
|
399
106
|
// astro.config.mjs
|
|
400
|
-
import
|
|
107
|
+
import remarkToc from 'remark-toc';
|
|
401
108
|
|
|
402
109
|
export default {
|
|
403
110
|
markdown: {
|
|
404
|
-
|
|
111
|
+
remarkPlugins: [/** ignored */]
|
|
405
112
|
},
|
|
406
113
|
integrations: [mdx({
|
|
407
|
-
remarkPlugins: [
|
|
114
|
+
remarkPlugins: [remarkToc],
|
|
115
|
+
// Astro defaults applied
|
|
116
|
+
extendPlugins: 'astroDefaults',
|
|
408
117
|
})],
|
|
118
|
+
}
|
|
409
119
|
```
|
|
410
120
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
### remarkPlugins
|
|
414
|
-
|
|
415
|
-
[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!
|
|
121
|
+
#### `false`
|
|
416
122
|
|
|
417
|
-
|
|
123
|
+
Astro's MDX files will not inherit any [`markdown` options](https://docs.astro.build/en/reference/configuration-reference/#markdown-options), nor will any Astro Markdown defaults be applied:
|
|
418
124
|
|
|
419
|
-
```js
|
|
125
|
+
```js "extendPlugins: false"
|
|
420
126
|
// astro.config.mjs
|
|
421
127
|
import remarkToc from 'remark-toc';
|
|
422
128
|
|
|
423
129
|
export default {
|
|
424
130
|
integrations: [mdx({
|
|
425
131
|
remarkPlugins: [remarkToc],
|
|
132
|
+
// Astro defaults not applied
|
|
133
|
+
extendPlugins: false,
|
|
426
134
|
})],
|
|
427
135
|
}
|
|
428
136
|
```
|
|
429
137
|
|
|
430
|
-
###
|
|
138
|
+
### `remarkRehype`
|
|
431
139
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
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).
|
|
140
|
+
Markdown content is transformed into HTML through remark-rehype which has [a number of options](https://github.com/remarkjs/remark-rehype#options).
|
|
435
141
|
|
|
436
|
-
|
|
142
|
+
You can set remark-rehype options in your config file:
|
|
437
143
|
|
|
438
144
|
```js
|
|
439
145
|
// astro.config.mjs
|
|
440
|
-
import rehypeMinifyHtml from 'rehype-minify';
|
|
441
|
-
|
|
442
146
|
export default {
|
|
443
147
|
integrations: [mdx({
|
|
444
|
-
|
|
148
|
+
remarkRehype: {
|
|
149
|
+
footnoteLabel: 'Catatan kaki',
|
|
150
|
+
footnoteBackLabel: 'Kembali ke konten',
|
|
151
|
+
},
|
|
445
152
|
})],
|
|
446
|
-
}
|
|
153
|
+
};
|
|
447
154
|
```
|
|
155
|
+
This inherits the configuration of [`markdown.remarkRehype`](https://docs.astro.build/en/reference/configuration-reference/#markdownremarkrehype). This behavior can be changed by configuring `extendPlugins`.
|
|
448
156
|
|
|
449
|
-
###
|
|
450
|
-
|
|
451
|
-
**Type:** `'markdown' | 'astroDefaults' | false`
|
|
452
|
-
|
|
453
|
-
**Default:** `'markdown'`
|
|
157
|
+
### `remarkPlugins`
|
|
454
158
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
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.
|
|
159
|
+
Browse [awesome-remark](https://github.com/remarkjs/awesome-remark) for a full curated list of [remark plugins](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) to extend your Markdown's capabilities.
|
|
458
160
|
|
|
459
|
-
This example applies [`remark-toc`](https://github.com/remarkjs/remark-toc) to Markdown
|
|
161
|
+
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).
|
|
460
162
|
|
|
461
163
|
```js
|
|
462
164
|
// astro.config.mjs
|
|
463
165
|
import remarkToc from 'remark-toc';
|
|
464
|
-
import rehypeMinify from 'rehype-minify';
|
|
465
166
|
|
|
466
167
|
export default {
|
|
467
|
-
markdown: {
|
|
468
|
-
// Applied to .md and .mdx files
|
|
469
|
-
remarkPlugins: [remarkToc],
|
|
470
|
-
},
|
|
471
168
|
integrations: [mdx({
|
|
472
|
-
|
|
473
|
-
rehypePlugins: [rehypeMinify],
|
|
169
|
+
remarkPlugins: [remarkToc],
|
|
474
170
|
})],
|
|
475
171
|
}
|
|
476
172
|
```
|
|
477
173
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
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):
|
|
174
|
+
### `rehypePlugins`
|
|
481
175
|
|
|
482
|
-
|
|
483
|
-
// astro.config.mjs
|
|
484
|
-
import remarkToc from 'remark-toc';
|
|
485
|
-
|
|
486
|
-
export default {
|
|
487
|
-
markdown: {
|
|
488
|
-
remarkPlugins: [/** ignored */]
|
|
489
|
-
},
|
|
490
|
-
integrations: [mdx({
|
|
491
|
-
remarkPlugins: [remarkToc],
|
|
492
|
-
// Astro defaults applied
|
|
493
|
-
extendPlugins: 'astroDefaults',
|
|
494
|
-
})],
|
|
495
|
-
}
|
|
496
|
-
```
|
|
176
|
+
Browse [awesome-rehype](https://github.com/rehypejs/awesome-rehype) for a full curated list of [Rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) to transform the HTML that your Markdown generates.
|
|
497
177
|
|
|
498
|
-
|
|
178
|
+
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).
|
|
499
179
|
|
|
500
|
-
|
|
180
|
+
This example applies the [`rehype-accessible-emojis`](https://www.npmjs.com/package/rehype-accessible-emojis) plugin to `.mdx` files. To customize plugin inheritance from your Markdown config or Astro's defaults, [see the `extendPlugins` option](#extendplugins).
|
|
501
181
|
|
|
502
|
-
```js
|
|
182
|
+
```js
|
|
503
183
|
// astro.config.mjs
|
|
504
|
-
import
|
|
184
|
+
import rehypeAccessibleEmojis from 'rehype-accessible-emojis';
|
|
505
185
|
|
|
506
186
|
export default {
|
|
507
187
|
integrations: [mdx({
|
|
508
|
-
|
|
509
|
-
// Astro defaults not applied
|
|
510
|
-
extendPlugins: false,
|
|
188
|
+
rehypePlugins: [rehypeAccessibleEmojis],
|
|
511
189
|
})],
|
|
512
190
|
}
|
|
513
191
|
```
|
|
514
192
|
|
|
515
|
-
### recmaPlugins
|
|
193
|
+
### `recmaPlugins`
|
|
516
194
|
|
|
517
195
|
These are plugins that modify the output [estree](https://github.com/estree/estree) directly. This is useful for modifying or injecting JavaScript variables in your MDX files.
|
|
518
196
|
|
|
519
197
|
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.
|
|
520
198
|
|
|
521
|
-
### remarkRehype
|
|
522
|
-
|
|
523
|
-
Markdown content is transformed into HTML through remark-rehype which has [a number of options](https://github.com/remarkjs/remark-rehype#options).
|
|
524
|
-
|
|
525
|
-
You can use remark-rehype options in your MDX integration config file like so:
|
|
526
|
-
|
|
527
|
-
```js
|
|
528
|
-
// astro.config.mjs
|
|
529
|
-
export default {
|
|
530
|
-
integrations: [mdx({
|
|
531
|
-
remarkRehype: {
|
|
532
|
-
footnoteLabel: 'Catatan kaki',
|
|
533
|
-
footnoteBackLabel: 'Kembali ke konten',
|
|
534
|
-
},
|
|
535
|
-
})],
|
|
536
|
-
};
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
This inherits the configuration of `markdown.remarkRehype`. This behavior can be changed by configuring `extendPlugins`.
|
|
540
|
-
|
|
541
199
|
## Examples
|
|
542
200
|
|
|
543
|
-
|
|
201
|
+
* 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.
|
|
544
202
|
|
|
545
203
|
## Troubleshooting
|
|
546
204
|
|
|
@@ -554,7 +212,8 @@ This package is maintained by Astro's Core team. You're welcome to submit an iss
|
|
|
554
212
|
|
|
555
213
|
## Changelog
|
|
556
214
|
|
|
557
|
-
See [CHANGELOG.md](CHANGELOG.md) for a history of changes to this integration.
|
|
215
|
+
See [CHANGELOG.md](https://github.com/withastro/astro/tree/main/packages/integrations/mdx/CHANGELOG.md) for a history of changes to this integration.
|
|
216
|
+
|
|
217
|
+
[astro-integration]: /en/guides/integrations-guide/
|
|
558
218
|
|
|
559
|
-
[astro-
|
|
560
|
-
[astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components
|
|
219
|
+
[astro-ui-frameworks]: /en/core-concepts/framework-components/#using-framework-components
|
package/dist/index.js
CHANGED
|
@@ -91,9 +91,14 @@ function mdx(mdxOptions = {}) {
|
|
|
91
91
|
transform(code, id) {
|
|
92
92
|
if (!id.endsWith(".mdx"))
|
|
93
93
|
return;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
94
|
+
const [moduleImports, moduleExports] = parseESM(code);
|
|
95
|
+
const importsFromJSXRuntime = moduleImports.filter(({ n }) => n === "astro/jsx-runtime").map(({ ss, se }) => code.substring(ss, se));
|
|
96
|
+
const hasFragmentImport = importsFromJSXRuntime.some(
|
|
97
|
+
(statement) => /[\s,{](Fragment,|Fragment\s*})/.test(statement)
|
|
98
|
+
);
|
|
99
|
+
if (!hasFragmentImport) {
|
|
100
|
+
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
101
|
+
}
|
|
97
102
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
98
103
|
if (!moduleExports.includes("url")) {
|
|
99
104
|
code += `
|
|
@@ -116,9 +121,16 @@ export function compiledContent() { throw new Error(${JSON.stringify(
|
|
|
116
121
|
)}) };`;
|
|
117
122
|
}
|
|
118
123
|
if (!moduleExports.includes("Content")) {
|
|
124
|
+
code = code.replace("export default MDXContent;", "");
|
|
119
125
|
code += `
|
|
120
|
-
export const Content = MDXContent
|
|
126
|
+
export const Content = (props = {}) => MDXContent({
|
|
127
|
+
...props,
|
|
128
|
+
components: { Fragment, ...props.components },
|
|
129
|
+
});
|
|
130
|
+
export default Content;`;
|
|
121
131
|
}
|
|
132
|
+
code += `
|
|
133
|
+
Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
122
134
|
if (command === "dev") {
|
|
123
135
|
code += `
|
|
124
136
|
if (import.meta.hot) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/mdx",
|
|
3
3
|
"description": "Use MDX within Astro",
|
|
4
|
-
"version": "0.12.
|
|
4
|
+
"version": "0.12.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@types/github-slugger": "^1.3.0",
|
|
47
47
|
"@types/mocha": "^9.1.1",
|
|
48
48
|
"@types/yargs-parser": "^21.0.0",
|
|
49
|
-
"astro": "1.6.
|
|
49
|
+
"astro": "1.6.15",
|
|
50
50
|
"astro-scripts": "0.0.9",
|
|
51
51
|
"chai": "^4.3.6",
|
|
52
52
|
"cheerio": "^1.0.0-rc.11",
|
package/src/index.ts
CHANGED
|
@@ -132,11 +132,18 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
132
132
|
transform(code, id) {
|
|
133
133
|
if (!id.endsWith('.mdx')) return;
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
const [moduleImports, moduleExports] = parseESM(code);
|
|
136
|
+
|
|
137
|
+
// Fragment import should already be injected, but check just to be safe.
|
|
138
|
+
const importsFromJSXRuntime = moduleImports
|
|
139
|
+
.filter(({ n }) => n === 'astro/jsx-runtime')
|
|
140
|
+
.map(({ ss, se }) => code.substring(ss, se));
|
|
141
|
+
const hasFragmentImport = importsFromJSXRuntime.some((statement) =>
|
|
142
|
+
/[\s,{](Fragment,|Fragment\s*})/.test(statement)
|
|
143
|
+
);
|
|
144
|
+
if (!hasFragmentImport) {
|
|
145
|
+
code = 'import { Fragment } from "astro/jsx-runtime"\n' + code;
|
|
146
|
+
}
|
|
140
147
|
|
|
141
148
|
const { fileUrl, fileId } = getFileInfo(id, config);
|
|
142
149
|
if (!moduleExports.includes('url')) {
|
|
@@ -156,9 +163,19 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
156
163
|
)}) };`;
|
|
157
164
|
}
|
|
158
165
|
if (!moduleExports.includes('Content')) {
|
|
159
|
-
|
|
166
|
+
// Make `Content` the default export so we can wrap `MDXContent` and pass in `Fragment`
|
|
167
|
+
code = code.replace('export default MDXContent;', '');
|
|
168
|
+
code += `\nexport const Content = (props = {}) => MDXContent({
|
|
169
|
+
...props,
|
|
170
|
+
components: { Fragment, ...props.components },
|
|
171
|
+
});
|
|
172
|
+
export default Content;`;
|
|
160
173
|
}
|
|
161
174
|
|
|
175
|
+
// Ensures styles and scripts are injected into a `<head>`
|
|
176
|
+
// When a layout is not applied
|
|
177
|
+
code += `\nContent[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`;
|
|
178
|
+
|
|
162
179
|
if (command === 'dev') {
|
|
163
180
|
// TODO: decline HMR updates until we have a stable approach
|
|
164
181
|
code += `\nif (import.meta.hot) {
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { parse } from 'node:path';
|
|
2
3
|
const components = await Astro.glob('../components/*.mdx');
|
|
3
4
|
---
|
|
4
5
|
|
|
5
6
|
<div data-default-export>
|
|
6
|
-
{components.map(Component =>
|
|
7
|
+
{components.map(Component => (
|
|
8
|
+
<div data-file={parse(Component.file).base}>
|
|
9
|
+
<Component.default />
|
|
10
|
+
</div>
|
|
11
|
+
))}
|
|
7
12
|
</div>
|
|
8
13
|
|
|
9
14
|
<div data-content-export>
|
|
10
|
-
{components.map(({ Content }) =>
|
|
15
|
+
{components.map(({ Content, file }) => (
|
|
16
|
+
<div data-file={parse(file).base}>
|
|
17
|
+
<Content />
|
|
18
|
+
</div>
|
|
19
|
+
))}
|
|
11
20
|
</div>
|
|
@@ -51,6 +51,41 @@ describe('MDX Component', () => {
|
|
|
51
51
|
expect(h1.textContent).to.equal('Hello component!');
|
|
52
52
|
expect(foo.textContent).to.equal('bar');
|
|
53
53
|
});
|
|
54
|
+
|
|
55
|
+
describe('with <Fragment>', () => {
|
|
56
|
+
it('supports top-level imports', async () => {
|
|
57
|
+
const html = await fixture.readFile('/w-fragment/index.html');
|
|
58
|
+
const { document } = parseHTML(html);
|
|
59
|
+
|
|
60
|
+
const h1 = document.querySelector('h1');
|
|
61
|
+
const p = document.querySelector('p');
|
|
62
|
+
|
|
63
|
+
expect(h1.textContent).to.equal('MDX containing <Fragment />');
|
|
64
|
+
expect(p.textContent).to.equal('bar');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
68
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
69
|
+
const { document } = parseHTML(html);
|
|
70
|
+
|
|
71
|
+
const h = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] h1');
|
|
72
|
+
const p = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] p');
|
|
73
|
+
|
|
74
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
75
|
+
expect(p.textContent).to.equal('bar');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('supports glob imports - <Content />', async () => {
|
|
79
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
80
|
+
const { document } = parseHTML(html);
|
|
81
|
+
|
|
82
|
+
const h = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] h1');
|
|
83
|
+
const p = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] p');
|
|
84
|
+
|
|
85
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
86
|
+
expect(p.textContent).to.equal('bar');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
54
89
|
});
|
|
55
90
|
|
|
56
91
|
describe('dev', () => {
|
|
@@ -108,5 +143,49 @@ describe('MDX Component', () => {
|
|
|
108
143
|
expect(h1.textContent).to.equal('Hello component!');
|
|
109
144
|
expect(foo.textContent).to.equal('bar');
|
|
110
145
|
});
|
|
146
|
+
|
|
147
|
+
describe('with <Fragment>', () => {
|
|
148
|
+
it('supports top-level imports', async () => {
|
|
149
|
+
const res = await fixture.fetch('/w-fragment');
|
|
150
|
+
expect(res.status).to.equal(200);
|
|
151
|
+
|
|
152
|
+
const html = await res.text();
|
|
153
|
+
const { document } = parseHTML(html);
|
|
154
|
+
|
|
155
|
+
const h1 = document.querySelector('h1');
|
|
156
|
+
const p = document.querySelector('p');
|
|
157
|
+
|
|
158
|
+
expect(h1.textContent).to.equal('MDX containing <Fragment />');
|
|
159
|
+
expect(p.textContent).to.equal('bar');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
163
|
+
const res = await fixture.fetch('/glob');
|
|
164
|
+
expect(res.status).to.equal(200);
|
|
165
|
+
|
|
166
|
+
const html = await res.text();
|
|
167
|
+
const { document } = parseHTML(html);
|
|
168
|
+
|
|
169
|
+
const h = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] h1');
|
|
170
|
+
const p = document.querySelector('[data-default-export] [data-file="WithFragment.mdx"] p');
|
|
171
|
+
|
|
172
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
173
|
+
expect(p.textContent).to.equal('bar');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('supports glob imports - <Content />', async () => {
|
|
177
|
+
const res = await fixture.fetch('/glob');
|
|
178
|
+
expect(res.status).to.equal(200);
|
|
179
|
+
|
|
180
|
+
const html = await res.text();
|
|
181
|
+
const { document } = parseHTML(html);
|
|
182
|
+
|
|
183
|
+
const h = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] h1');
|
|
184
|
+
const p = document.querySelector('[data-content-export] [data-file="WithFragment.mdx"] p');
|
|
185
|
+
|
|
186
|
+
expect(h.textContent).to.equal('MDX containing <Fragment />');
|
|
187
|
+
expect(p.textContent).to.equal('bar');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
111
190
|
});
|
|
112
191
|
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import mdx from '@astrojs/mdx';
|
|
2
|
+
|
|
3
|
+
import { expect } from 'chai';
|
|
4
|
+
import { parseHTML } from 'linkedom';
|
|
5
|
+
import { loadFixture } from '../../../astro/test/test-utils.js';
|
|
6
|
+
|
|
7
|
+
describe('MDX slots', () => {
|
|
8
|
+
let fixture;
|
|
9
|
+
|
|
10
|
+
before(async () => {
|
|
11
|
+
fixture = await loadFixture({
|
|
12
|
+
root: new URL('./fixtures/mdx-slots/', import.meta.url),
|
|
13
|
+
integrations: [mdx()],
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('build', () => {
|
|
18
|
+
before(async () => {
|
|
19
|
+
await fixture.build();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('supports top-level imports', async () => {
|
|
23
|
+
const html = await fixture.readFile('/index.html');
|
|
24
|
+
const { document } = parseHTML(html);
|
|
25
|
+
|
|
26
|
+
const h1 = document.querySelector('h1');
|
|
27
|
+
const defaultSlot = document.querySelector('[data-default-slot]');
|
|
28
|
+
const namedSlot = document.querySelector('[data-named-slot]');
|
|
29
|
+
|
|
30
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
31
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
32
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
36
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
37
|
+
const { document } = parseHTML(html);
|
|
38
|
+
|
|
39
|
+
const h1 = document.querySelector('[data-default-export] h1');
|
|
40
|
+
const defaultSlot = document.querySelector('[data-default-export] [data-default-slot]');
|
|
41
|
+
const namedSlot = document.querySelector('[data-default-export] [data-named-slot]');
|
|
42
|
+
|
|
43
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
44
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
45
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('supports glob imports - <Content />', async () => {
|
|
49
|
+
const html = await fixture.readFile('/glob/index.html');
|
|
50
|
+
const { document } = parseHTML(html);
|
|
51
|
+
|
|
52
|
+
const h1 = document.querySelector('[data-content-export] h1');
|
|
53
|
+
const defaultSlot = document.querySelector('[data-content-export] [data-default-slot]');
|
|
54
|
+
const namedSlot = document.querySelector('[data-content-export] [data-named-slot]');
|
|
55
|
+
|
|
56
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
57
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
58
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('dev', () => {
|
|
63
|
+
let devServer;
|
|
64
|
+
|
|
65
|
+
before(async () => {
|
|
66
|
+
devServer = await fixture.startDevServer();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
after(async () => {
|
|
70
|
+
await devServer.stop();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('supports top-level imports', async () => {
|
|
74
|
+
const res = await fixture.fetch('/');
|
|
75
|
+
|
|
76
|
+
expect(res.status).to.equal(200);
|
|
77
|
+
|
|
78
|
+
const html = await res.text();
|
|
79
|
+
const { document } = parseHTML(html);
|
|
80
|
+
|
|
81
|
+
const h1 = document.querySelector('h1');
|
|
82
|
+
const defaultSlot = document.querySelector('[data-default-slot]');
|
|
83
|
+
const namedSlot = document.querySelector('[data-named-slot]');
|
|
84
|
+
|
|
85
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
86
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
87
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('supports glob imports - <Component.default />', async () => {
|
|
91
|
+
const res = await fixture.fetch('/glob');
|
|
92
|
+
|
|
93
|
+
expect(res.status).to.equal(200);
|
|
94
|
+
|
|
95
|
+
const html = await res.text();
|
|
96
|
+
const { document } = parseHTML(html);
|
|
97
|
+
|
|
98
|
+
const h1 = document.querySelector('[data-default-export] h1');
|
|
99
|
+
const defaultSlot = document.querySelector('[data-default-export] [data-default-slot]');
|
|
100
|
+
const namedSlot = document.querySelector('[data-default-export] [data-named-slot]');
|
|
101
|
+
|
|
102
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
103
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
104
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('supports glob imports - <Content />', async () => {
|
|
108
|
+
const res = await fixture.fetch('/glob');
|
|
109
|
+
|
|
110
|
+
expect(res.status).to.equal(200);
|
|
111
|
+
|
|
112
|
+
const html = await res.text();
|
|
113
|
+
const { document } = parseHTML(html);
|
|
114
|
+
|
|
115
|
+
const h1 = document.querySelector('[data-content-export] h1');
|
|
116
|
+
const defaultSlot = document.querySelector('[data-content-export] [data-default-slot]');
|
|
117
|
+
const namedSlot = document.querySelector('[data-content-export] [data-named-slot]');
|
|
118
|
+
|
|
119
|
+
expect(h1.textContent).to.equal('Hello slotted component!');
|
|
120
|
+
expect(defaultSlot.textContent).to.equal('Default content.');
|
|
121
|
+
expect(namedSlot.textContent).to.equal('Content for named slot.');
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|