@astrojs/mdx 0.3.1 → 0.4.0
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 +6 -0
- package/README.md +33 -9
- package/dist/index.js +32 -9
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +18 -1
- package/package.json +6 -5
- package/src/index.ts +36 -12
- package/src/utils.ts +22 -1
- package/test/fixtures/mdx-frontmatter/src/layouts/Base.astro +18 -0
- package/test/fixtures/mdx-frontmatter/src/pages/index.mdx +2 -1
- package/test/mdx-frontmatter.test.js +31 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[36m@astrojs/mdx:build: [0mcache hit, replaying output [2mc4afb89e8a455a28[0m
|
|
2
|
+
[36m@astrojs/mdx:build: [0m
|
|
3
|
+
[36m@astrojs/mdx:build: [0m> @astrojs/mdx@0.4.0 build /home/runner/work/astro/astro/packages/integrations/mdx
|
|
4
|
+
[36m@astrojs/mdx:build: [0m> astro-scripts build "src/**/*.ts" && tsc
|
|
5
|
+
[36m@astrojs/mdx:build: [0m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @astrojs/mdx
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#4088](https://github.com/withastro/astro/pull/4088) [`1743fe140`](https://github.com/withastro/astro/commit/1743fe140eb58d60e26cbd11a066bb60de046e0c) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support "layout" frontmatter property
|
|
8
|
+
|
|
3
9
|
## 0.3.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -136,15 +136,37 @@ const posts = await Astro.glob('./*.mdx');
|
|
|
136
136
|
|
|
137
137
|
### Layouts
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
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:
|
|
140
140
|
|
|
141
|
-
```
|
|
142
|
-
|
|
141
|
+
```yaml
|
|
142
|
+
---
|
|
143
|
+
layout: '../layouts/BaseLayout.astro'
|
|
144
|
+
title: 'My Blog Post'
|
|
145
|
+
---
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Then, you can retrieve all other frontmatter properties from your layout via the `content` property, and render your MDX using the default [`<slot />`](https://docs.astro.build/en/core-concepts/astro-components/#slots):
|
|
143
149
|
|
|
144
|
-
|
|
150
|
+
```astro
|
|
151
|
+
---
|
|
152
|
+
// src/layouts/BaseLayout.astro
|
|
153
|
+
const { content } = Astro.props;
|
|
154
|
+
---
|
|
155
|
+
<html>
|
|
156
|
+
<head>
|
|
157
|
+
<title>{content.title}</title>
|
|
158
|
+
</head>
|
|
159
|
+
<body>
|
|
160
|
+
<h1>{content.title}</h1>
|
|
161
|
+
<!-- Rendered MDX will be passed into the default slot. -->
|
|
162
|
+
<slot />
|
|
163
|
+
</body>
|
|
164
|
+
</html>
|
|
145
165
|
```
|
|
146
166
|
|
|
147
|
-
|
|
167
|
+
#### Importing layouts manually
|
|
168
|
+
|
|
169
|
+
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:
|
|
148
170
|
|
|
149
171
|
```mdx
|
|
150
172
|
---
|
|
@@ -155,9 +177,11 @@ publishDate: '21 September 2022'
|
|
|
155
177
|
---
|
|
156
178
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
157
179
|
|
|
158
|
-
|
|
159
|
-
|
|
180
|
+
function fancyJsHelper() {
|
|
181
|
+
return "Try doing that with YAML!";
|
|
182
|
+
}
|
|
160
183
|
|
|
184
|
+
<BaseLayout title={frontmatter.title} fancyJsHelper={fancyJsHelper}>
|
|
161
185
|
Welcome to my new Astro blog, using MDX!
|
|
162
186
|
</BaseLayout>
|
|
163
187
|
```
|
|
@@ -166,12 +190,12 @@ Then, your values are available to you through `Astro.props` in your layout, and
|
|
|
166
190
|
```astro
|
|
167
191
|
---
|
|
168
192
|
// src/layouts/BaseLayout.astro
|
|
169
|
-
const { title,
|
|
193
|
+
const { title, fancyJsHelper } = Astro.props;
|
|
170
194
|
---
|
|
171
195
|
<!-- -->
|
|
172
196
|
<h1>{title}</h1>
|
|
173
197
|
<slot />
|
|
174
|
-
<p>
|
|
198
|
+
<p>{fancyJsHelper()}</p>
|
|
175
199
|
<!-- -->
|
|
176
200
|
```
|
|
177
201
|
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import remarkMdxFrontmatter from "remark-mdx-frontmatter";
|
|
|
8
8
|
import remarkShikiTwoslash from "remark-shiki-twoslash";
|
|
9
9
|
import remarkSmartypants from "remark-smartypants";
|
|
10
10
|
import remarkPrism from "./remark-prism.js";
|
|
11
|
-
import { getFileInfo } from "./utils.js";
|
|
11
|
+
import { getFileInfo, getFrontmatter } from "./utils.js";
|
|
12
12
|
const DEFAULT_REMARK_PLUGINS = [remarkGfm, remarkSmartypants];
|
|
13
13
|
function handleExtends(config, defaults = []) {
|
|
14
14
|
if (Array.isArray(config))
|
|
@@ -42,19 +42,42 @@ function mdx(mdxOptions = {}) {
|
|
|
42
42
|
...mdxOptions.frontmatterOptions
|
|
43
43
|
}
|
|
44
44
|
]);
|
|
45
|
+
const configuredMdxPlugin = mdxPlugin({
|
|
46
|
+
remarkPlugins,
|
|
47
|
+
rehypePlugins,
|
|
48
|
+
jsx: true,
|
|
49
|
+
jsxImportSource: "astro",
|
|
50
|
+
format: "mdx",
|
|
51
|
+
mdExtensions: []
|
|
52
|
+
});
|
|
45
53
|
updateConfig({
|
|
46
54
|
vite: {
|
|
47
55
|
plugins: [
|
|
48
56
|
{
|
|
49
57
|
enforce: "pre",
|
|
50
|
-
...
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
...configuredMdxPlugin,
|
|
59
|
+
async transform(code, id) {
|
|
60
|
+
var _a, _b;
|
|
61
|
+
if (!id.endsWith(".mdx"))
|
|
62
|
+
return;
|
|
63
|
+
const mdxPluginTransform = (_a = configuredMdxPlugin.transform) == null ? void 0 : _a.bind(this);
|
|
64
|
+
if ((_b = mdxOptions.frontmatterOptions) == null ? void 0 : _b.parsers) {
|
|
65
|
+
return mdxPluginTransform == null ? void 0 : mdxPluginTransform(code, id);
|
|
66
|
+
}
|
|
67
|
+
const frontmatter = getFrontmatter(code, id);
|
|
68
|
+
if (frontmatter.layout) {
|
|
69
|
+
const { layout, ...content } = frontmatter;
|
|
70
|
+
code += `
|
|
71
|
+
export default async function({ children }) {
|
|
72
|
+
const Layout = (await import(${JSON.stringify(
|
|
73
|
+
frontmatter.layout
|
|
74
|
+
)})).default;
|
|
75
|
+
return <Layout content={${JSON.stringify(
|
|
76
|
+
content
|
|
77
|
+
)}}>{children}</Layout> }`;
|
|
78
|
+
}
|
|
79
|
+
return mdxPluginTransform == null ? void 0 : mdxPluginTransform(code, id);
|
|
80
|
+
}
|
|
58
81
|
},
|
|
59
82
|
{
|
|
60
83
|
name: "@astrojs/mdx",
|
package/dist/utils.d.ts
CHANGED
|
@@ -5,4 +5,11 @@ interface FileInfo {
|
|
|
5
5
|
}
|
|
6
6
|
/** @see 'vite-plugin-utils' for source */
|
|
7
7
|
export declare function getFileInfo(id: string, config: AstroConfig): FileInfo;
|
|
8
|
+
/**
|
|
9
|
+
* Match YAML exception handling from Astro core errors
|
|
10
|
+
* @see 'astro/src/core/errors.ts'
|
|
11
|
+
*/
|
|
12
|
+
export declare function getFrontmatter(code: string, id: string): {
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
};
|
|
8
15
|
export {};
|
package/dist/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import matter from "gray-matter";
|
|
1
2
|
function appendForwardSlash(path) {
|
|
2
3
|
return path.endsWith("/") ? path : path + "/";
|
|
3
4
|
}
|
|
@@ -25,6 +26,22 @@ function getFileInfo(id, config) {
|
|
|
25
26
|
}
|
|
26
27
|
return { fileId, fileUrl };
|
|
27
28
|
}
|
|
29
|
+
function getFrontmatter(code, id) {
|
|
30
|
+
try {
|
|
31
|
+
return matter(code).data;
|
|
32
|
+
} catch (e) {
|
|
33
|
+
if (e.name === "YAMLException") {
|
|
34
|
+
const err = e;
|
|
35
|
+
err.id = id;
|
|
36
|
+
err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
|
|
37
|
+
err.message = e.reason;
|
|
38
|
+
throw err;
|
|
39
|
+
} else {
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
28
44
|
export {
|
|
29
|
-
getFileInfo
|
|
45
|
+
getFileInfo,
|
|
46
|
+
getFrontmatter
|
|
30
47
|
};
|
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.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -28,21 +28,22 @@
|
|
|
28
28
|
"@mdx-js/mdx": "^2.1.2",
|
|
29
29
|
"@mdx-js/rollup": "^2.1.1",
|
|
30
30
|
"es-module-lexer": "^0.10.5",
|
|
31
|
+
"gray-matter": "^4.0.3",
|
|
31
32
|
"prismjs": "^1.28.0",
|
|
32
33
|
"rehype-raw": "^6.1.1",
|
|
34
|
+
"remark-frontmatter": "^4.0.1",
|
|
33
35
|
"remark-gfm": "^3.0.1",
|
|
36
|
+
"remark-mdx-frontmatter": "^2.0.2",
|
|
34
37
|
"remark-shiki-twoslash": "^3.1.0",
|
|
35
38
|
"remark-smartypants": "^2.0.0",
|
|
36
39
|
"shiki": "^0.10.1",
|
|
37
|
-
"unist-util-visit": "^4.1.0"
|
|
38
|
-
"remark-frontmatter": "^4.0.1",
|
|
39
|
-
"remark-mdx-frontmatter": "^2.0.2"
|
|
40
|
+
"unist-util-visit": "^4.1.0"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@types/chai": "^4.3.1",
|
|
43
44
|
"@types/mocha": "^9.1.1",
|
|
44
45
|
"@types/yargs-parser": "^21.0.0",
|
|
45
|
-
"astro": "1.0.0-rc.
|
|
46
|
+
"astro": "1.0.0-rc.3",
|
|
46
47
|
"astro-scripts": "0.0.6",
|
|
47
48
|
"chai": "^4.3.6",
|
|
48
49
|
"linkedom": "^0.14.12",
|
package/src/index.ts
CHANGED
|
@@ -9,8 +9,9 @@ import type { RemarkMdxFrontmatterOptions } from 'remark-mdx-frontmatter';
|
|
|
9
9
|
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
|
|
10
10
|
import remarkShikiTwoslash from 'remark-shiki-twoslash';
|
|
11
11
|
import remarkSmartypants from 'remark-smartypants';
|
|
12
|
+
import type { Plugin as VitePlugin } from 'vite';
|
|
12
13
|
import remarkPrism from './remark-prism.js';
|
|
13
|
-
import { getFileInfo } from './utils.js';
|
|
14
|
+
import { getFileInfo, getFrontmatter } from './utils.js';
|
|
14
15
|
|
|
15
16
|
type WithExtends<T> = T | { extends: T };
|
|
16
17
|
|
|
@@ -68,24 +69,47 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
68
69
|
},
|
|
69
70
|
]);
|
|
70
71
|
|
|
72
|
+
const configuredMdxPlugin = mdxPlugin({
|
|
73
|
+
remarkPlugins,
|
|
74
|
+
rehypePlugins,
|
|
75
|
+
jsx: true,
|
|
76
|
+
jsxImportSource: 'astro',
|
|
77
|
+
// Note: disable `.md` support
|
|
78
|
+
format: 'mdx',
|
|
79
|
+
mdExtensions: [],
|
|
80
|
+
});
|
|
81
|
+
|
|
71
82
|
updateConfig({
|
|
72
83
|
vite: {
|
|
73
84
|
plugins: [
|
|
74
85
|
{
|
|
75
86
|
enforce: 'pre',
|
|
76
|
-
...
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
...configuredMdxPlugin,
|
|
88
|
+
// Override transform to inject layouts before MDX compilation
|
|
89
|
+
async transform(this, code, id) {
|
|
90
|
+
if (!id.endsWith('.mdx')) return;
|
|
91
|
+
|
|
92
|
+
const mdxPluginTransform = configuredMdxPlugin.transform?.bind(this);
|
|
93
|
+
// If user overrides our default YAML parser,
|
|
94
|
+
// do not attempt to parse the `layout` via gray-matter
|
|
95
|
+
if (mdxOptions.frontmatterOptions?.parsers) {
|
|
96
|
+
return mdxPluginTransform?.(code, id);
|
|
97
|
+
}
|
|
98
|
+
const frontmatter = getFrontmatter(code, id);
|
|
99
|
+
if (frontmatter.layout) {
|
|
100
|
+
const { layout, ...content } = frontmatter;
|
|
101
|
+
code += `\nexport default async function({ children }) {\nconst Layout = (await import(${JSON.stringify(
|
|
102
|
+
frontmatter.layout
|
|
103
|
+
)})).default;\nreturn <Layout content={${JSON.stringify(
|
|
104
|
+
content
|
|
105
|
+
)}}>{children}</Layout> }`;
|
|
106
|
+
}
|
|
107
|
+
return mdxPluginTransform?.(code, id);
|
|
108
|
+
},
|
|
85
109
|
},
|
|
86
110
|
{
|
|
87
111
|
name: '@astrojs/mdx',
|
|
88
|
-
transform(code
|
|
112
|
+
transform(code, id) {
|
|
89
113
|
if (!id.endsWith('.mdx')) return;
|
|
90
114
|
const [, moduleExports] = parseESM(code);
|
|
91
115
|
|
|
@@ -113,7 +137,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
|
|
|
113
137
|
return code;
|
|
114
138
|
},
|
|
115
139
|
},
|
|
116
|
-
],
|
|
140
|
+
] as VitePlugin[],
|
|
117
141
|
},
|
|
118
142
|
});
|
|
119
143
|
},
|
package/src/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AstroConfig } from 'astro';
|
|
1
|
+
import type { AstroConfig, SSRError } from 'astro';
|
|
2
|
+
import matter from 'gray-matter';
|
|
2
3
|
|
|
3
4
|
function appendForwardSlash(path: string) {
|
|
4
5
|
return path.endsWith('/') ? path : path + '/';
|
|
@@ -37,3 +38,23 @@ export function getFileInfo(id: string, config: AstroConfig): FileInfo {
|
|
|
37
38
|
}
|
|
38
39
|
return { fileId, fileUrl };
|
|
39
40
|
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Match YAML exception handling from Astro core errors
|
|
44
|
+
* @see 'astro/src/core/errors.ts'
|
|
45
|
+
*/
|
|
46
|
+
export function getFrontmatter(code: string, id: string) {
|
|
47
|
+
try {
|
|
48
|
+
return matter(code).data;
|
|
49
|
+
} catch (e: any) {
|
|
50
|
+
if (e.name === 'YAMLException') {
|
|
51
|
+
const err: SSRError = e;
|
|
52
|
+
err.id = id;
|
|
53
|
+
err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
|
|
54
|
+
err.message = e.reason;
|
|
55
|
+
throw err;
|
|
56
|
+
} else {
|
|
57
|
+
throw e;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
const { content = { title: "Didn't work" } } = Astro.props;
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<!DOCTYPE html>
|
|
6
|
+
<html lang="en">
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8">
|
|
9
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
+
<title>{content.title}</title>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<h1>{content.title}</h1>
|
|
15
|
+
<p data-layout-rendered>Layout rendered!</p>
|
|
16
|
+
<slot />
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import mdx from '@astrojs/mdx';
|
|
2
2
|
|
|
3
3
|
import { expect } from 'chai';
|
|
4
|
+
import { parseHTML } from 'linkedom';
|
|
4
5
|
import { loadFixture } from '../../../astro/test/test-utils.js';
|
|
5
6
|
|
|
6
7
|
const FIXTURE_ROOT = new URL('./fixtures/mdx-frontmatter/', import.meta.url);
|
|
@@ -26,6 +27,36 @@ describe('MDX frontmatter', () => {
|
|
|
26
27
|
expect(titles).to.include('Using YAML frontmatter');
|
|
27
28
|
});
|
|
28
29
|
|
|
30
|
+
it('renders layout from "layout" frontmatter property', async () => {
|
|
31
|
+
const fixture = await loadFixture({
|
|
32
|
+
root: FIXTURE_ROOT,
|
|
33
|
+
integrations: [mdx()],
|
|
34
|
+
});
|
|
35
|
+
await fixture.build();
|
|
36
|
+
|
|
37
|
+
const html = await fixture.readFile('/index.html');
|
|
38
|
+
const { document } = parseHTML(html);
|
|
39
|
+
|
|
40
|
+
const layoutParagraph = document.querySelector('[data-layout-rendered]');
|
|
41
|
+
|
|
42
|
+
expect(layoutParagraph).to.not.be.null;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('passes frontmatter to layout via "content" prop', async () => {
|
|
46
|
+
const fixture = await loadFixture({
|
|
47
|
+
root: FIXTURE_ROOT,
|
|
48
|
+
integrations: [mdx()],
|
|
49
|
+
});
|
|
50
|
+
await fixture.build();
|
|
51
|
+
|
|
52
|
+
const html = await fixture.readFile('/index.html');
|
|
53
|
+
const { document } = parseHTML(html);
|
|
54
|
+
|
|
55
|
+
const h1 = document.querySelector('h1');
|
|
56
|
+
|
|
57
|
+
expect(h1.textContent).to.equal('Using YAML frontmatter');
|
|
58
|
+
});
|
|
59
|
+
|
|
29
60
|
it('extracts frontmatter to "customFrontmatter" export when configured', async () => {
|
|
30
61
|
const fixture = await loadFixture({
|
|
31
62
|
root: new URL('./fixtures/mdx-custom-frontmatter-name/', import.meta.url),
|