@astrojs/mdx 0.0.0-rc-20220721064837

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.
@@ -0,0 +1,5 @@
1
+ @astrojs/mdx:build: cache hit, replaying output 3b9c619d3889cd87
2
+ @astrojs/mdx:build: 
3
+ @astrojs/mdx:build: > @astrojs/mdx@0.2.1 build /Users/fks/Code/astro/packages/integrations/mdx
4
+ @astrojs/mdx:build: > astro-scripts build "src/**/*.ts" && tsc
5
+ @astrojs/mdx:build: 
@@ -0,0 +1 @@
1
+ @astrojs/mdx:test: cache hit, replaying output 2250434e5c0f5a46
package/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ # @astrojs/mdx
2
+
3
+ ## 0.0.0-rc-20220721064837
4
+
5
+ ### Minor Changes
6
+
7
+ - [#3977](https://github.com/withastro/astro/pull/3977) [`19433eb4a`](https://github.com/withastro/astro/commit/19433eb4a4441522f68492ca914ad2ab4f061343) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add remarkPlugins and rehypePlugins to config, with the same default plugins as our standard Markdown parser
8
+
9
+ * [#3995](https://github.com/withastro/astro/pull/3995) [`b2b367c96`](https://github.com/withastro/astro/commit/b2b367c969493aaf21c974064beb241d05228066) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Support YAML frontmatter in MDX files
10
+
11
+ ### Patch Changes
12
+
13
+ - [#3981](https://github.com/withastro/astro/pull/3981) [`61fec6304`](https://github.com/withastro/astro/commit/61fec63044e1585348e8405bee6fdf4dec635efa) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Include page url in MDX glob result
14
+
15
+ ## 0.2.1
16
+
17
+ ### Patch Changes
18
+
19
+ - [#3937](https://github.com/withastro/astro/pull/3937) [`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e) Thanks [@delucis](https://github.com/delucis)! - Roll back supported Node engines
20
+
21
+ ## 0.2.0
22
+
23
+ ### Minor Changes
24
+
25
+ - [#3914](https://github.com/withastro/astro/pull/3914) [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86) Thanks [@ran-dall](https://github.com/ran-dall)! - Rollback supported `node@16` version. Minimum versions are now `node@14.20.0` or `node@16.14.0`.
26
+
27
+ ## 0.1.1
28
+
29
+ ### Patch Changes
30
+
31
+ - [#3885](https://github.com/withastro/astro/pull/3885) [`bf5d1cc1e`](https://github.com/withastro/astro/commit/bf5d1cc1e71da38a14658c615e9481f2145cc6e7) Thanks [@delucis](https://github.com/delucis)! - Integration README fixes
32
+
33
+ ## 0.1.0
34
+
35
+ ### Minor Changes
36
+
37
+ - [#3871](https://github.com/withastro/astro/pull/3871) [`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update supported `node` versions. Minimum versions are now `node@14.20.0` or `node@16.16.0`.
38
+
39
+ ## 0.0.3
40
+
41
+ ### Patch Changes
42
+
43
+ - [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages
44
+
45
+ ## 0.0.2
46
+
47
+ ### Patch Changes
48
+
49
+ - [#3706](https://github.com/withastro/astro/pull/3706) [`032ad1c0`](https://github.com/withastro/astro/commit/032ad1c047a62dd663067cc562537d16f2872aa7) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Initial release! 🎉
package/LICENSE ADDED
@@ -0,0 +1,61 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Fred K. Schott
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+
24
+ """
25
+ This license applies to parts of the `packages/create-astro` and `packages/astro` subdirectories originating from the https://github.com/sveltejs/kit repository:
26
+
27
+ Copyright (c) 2020 [these people](https://github.com/sveltejs/kit/graphs/contributors)
28
+
29
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
30
+
31
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34
+ """
35
+
36
+
37
+ """
38
+ This license applies to parts of the `packages/create-astro` and `packages/astro` subdirectories originating from the https://github.com/vitejs/vite repository:
39
+
40
+ MIT License
41
+
42
+ Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors
43
+
44
+ Permission is hereby granted, free of charge, to any person obtaining a copy
45
+ of this software and associated documentation files (the "Software"), to deal
46
+ in the Software without restriction, including without limitation the rights
47
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48
+ copies of the Software, and to permit persons to whom the Software is
49
+ furnished to do so, subject to the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be included in all
52
+ copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
60
+ SOFTWARE.
61
+ """
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ # @astrojs/mdx 📝
2
+
3
+ This **[Astro integration][astro-integration]** enables the usage of [MDX](https://mdxjs.com/) components and allows you to create pages as `.mdx` files.
4
+
5
+ - <strong>[Why MDX?](#why-mdx)</strong>
6
+ - <strong>[Installation](#installation)</strong>
7
+ - <strong>[Usage](#usage)</strong>
8
+ - <strong>[Configuration](#configuration)</strong>
9
+ - <strong>[Examples](#examples)</strong>
10
+ - <strong>[Troubleshooting](#troubleshooting)</strong>
11
+ - <strong>[Contributing](#contributing)</strong>
12
+ - <strong>[Changelog](#changelog)</strong>
13
+
14
+ ## Why MDX?
15
+
16
+ MDX is the defacto solution for embedding components, such as interactive charts or alerts, within Markdown content. If you have existing content authored in MDX, this integration makes migrating to Astro a breeze.
17
+
18
+ **Want to learn more about MDX before using this integration?**
19
+ Check out [“What is MDX?”](https://mdxjs.com/docs/what-is-mdx/), a deep-dive on the MDX format.
20
+
21
+ ## Installation
22
+
23
+ <details>
24
+ <summary>Quick Install</summary>
25
+
26
+ The `astro add` command-line tool automates the installation for you. Run one of the following commands in a new terminal window. (If you aren't sure which package manager you're using, run the first command.) Then, follow the prompts, and type "y" in the terminal (meaning "yes") for each one.
27
+
28
+ ```sh
29
+ # Using NPM
30
+ npx astro add mdx
31
+ # Using Yarn
32
+ yarn astro add mdx
33
+ # Using PNPM
34
+ pnpx astro add mdx
35
+ ```
36
+
37
+ Then, restart the dev server by typing `CTRL-C` and then `npm run astro dev` in the terminal window that was running Astro.
38
+
39
+ Because this command is new, it might not properly set things up. If that happens, [feel free to log an issue on our GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
40
+ </details>
41
+
42
+ <details>
43
+ <summary>Manual Install</summary>
44
+
45
+ First, install the `@astrojs/mdx` package using your package manager. If you're using npm or aren't sure, run this in the terminal:
46
+
47
+ ```sh
48
+ npm install @astrojs/mdx
49
+ ```
50
+
51
+ Then, apply this integration to your `astro.config.*` file using the `integrations` property:
52
+
53
+ __`astro.config.mjs`__
54
+
55
+ ```js
56
+ import { defineConfig } from 'astro/config';
57
+ import mdx from '@astrojs/mdx';
58
+
59
+ export default defineConfig({
60
+ // ...
61
+ integrations: [mdx()],
62
+ });
63
+ ```
64
+
65
+ Finally, restart the dev server.
66
+ </details>
67
+
68
+ ## Usage
69
+
70
+ To write your first MDX page in Astro, head to our [UI framework documentation][astro-ui-frameworks]. You'll explore:
71
+ - 📦 how framework components are loaded,
72
+ - 💧 client-side hydration options, and
73
+ - 🪆 opportunities to mix and nest frameworks together
74
+
75
+ [**Client Directives**](https://docs.astro.build/en/reference/directives-reference/#client-directives) are still required in `.mdx` files.
76
+
77
+ > **Note**: `.mdx` files adhere to strict JSX syntax rather than Astro's HTML-like syntax.
78
+
79
+ Also check our [Astro Integration Documentation][astro-integration] for more on integrations.
80
+
81
+ ### Variables
82
+
83
+ 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.
84
+
85
+ For instance, you can export a `title` field from an MDX page or component to use as a heading with `{JSX expressions}`:
86
+
87
+ ```mdx
88
+ export const title = 'My first MDX post'
89
+
90
+ # {title}
91
+ ```
92
+
93
+ This `title` will be accessible from `import` and [glob](https://docs.astro.build/en/reference/api-reference/#astroglob) statements as well:
94
+
95
+ ```astro
96
+ ---
97
+ // src/pages/index.astro
98
+ const posts = await Astro.glob('./*.mdx');
99
+ ---
100
+
101
+ {posts.map(post => <p>{post.title}</p>)}
102
+ ```
103
+
104
+ See [the official "how MDX works" guide](https://mdxjs.com/docs/using-mdx/#how-mdx-works) for more on MDX variables.
105
+
106
+ ### Frontmatter
107
+
108
+ Astro also supports YAML-based frontmatter out-of-the-box using the [remark-mdx-frontmatter](https://github.com/remcohaszing/remark-mdx-frontmatter) plugin. By default, all variables declared in a frontmatter fence (`---`) will be accessible via the `frontmatter` export. See the `frontmatterOptions` configuration to customize this behavior.
109
+
110
+ For example, we can add a `title` and `publishDate` to an MDX page or component like so:
111
+
112
+ ```mdx
113
+ ---
114
+ title: 'My first MDX post'
115
+ publishDate: '21 September 2022'
116
+ ---
117
+
118
+ # {frontmatter.title}
119
+ ```
120
+
121
+ 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!
122
+
123
+ ```astro
124
+ ---
125
+ // src/pages/index.astro
126
+ const posts = await Astro.glob('./*.mdx');
127
+ ---
128
+
129
+ {posts.map(post => (
130
+ <Fragment>
131
+ <h2>{post.frontmatter.title}</h2>
132
+ <time>{post.frontmatter.publishDate}</time>
133
+ </Fragment>
134
+ ))}
135
+ ```
136
+
137
+ ## Configuration
138
+
139
+ <details>
140
+ <summary><strong>remarkPlugins</strong></summary>
141
+
142
+ **Default plugins:** [remark-gfm](https://github.com/remarkjs/remark-gfm), [remark-smartypants](https://github.com/silvenon/remark-smartypants)
143
+
144
+ [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!
145
+
146
+ We apply [GitHub-flavored Markdown](https://github.com/remarkjs/remark-gfm) and [Smartypants](https://github.com/silvenon/remark-smartypants) by default. This brings some niceties like auto-generating clickable links from text (ex. `https://example.com`) and formatting quotes for readability. When applying your own plugins, you can choose to preserve or remove these defaults.
147
+
148
+ To apply plugins _while preserving_ Astro's default plugins, use a nested `extends` object like so:
149
+
150
+ ```js
151
+ // astro.config.mjs
152
+ import remarkToc from 'remark-toc';
153
+
154
+ export default {
155
+ integrations: [mdx({
156
+ // apply remark-toc alongside GitHub-flavored markdown and Smartypants
157
+ remarkPlugins: { extends: [remarkToc] },
158
+ })],
159
+ }
160
+ ```
161
+
162
+ To apply plugins _without_ Astro's defaults, you can apply a plain array:
163
+
164
+ ```js
165
+ // astro.config.mjs
166
+ import remarkToc from 'remark-toc';
167
+
168
+ export default {
169
+ integrations: [mdx({
170
+ // apply remark-toc alone, removing other defaults
171
+ remarkPlugins: [remarkToc],
172
+ })],
173
+ }
174
+ ```
175
+
176
+ </details>
177
+
178
+ <details>
179
+ <summary><strong>rehypePlugins</strong></summary>
180
+
181
+ **Default plugins:** none
182
+
183
+ [Rehype plugins](https://github.com/rehypejs/rehype/blob/main/doc/plugins.md) allow you to transform the HTML that your Markdown generates. We recommend checking the [Remark plugin](https://github.com/remarkjs/remark/blob/main/doc/plugins.md) catalog first _before_ considering rehype plugins, since most users want to transform their Markdown syntax instead. If HTML transforms are what you need, we encourage you to browse [awesome-rehype](https://github.com/rehypejs/awesome-rehype) for a full curated list of plugins!
184
+
185
+ To apply rehype plugins, use the `rehypePlugins` configuration option like so:
186
+
187
+ ```js
188
+ // astro.config.mjs
189
+ import rehypeMinifyHtml from 'rehype-minify';
190
+
191
+ export default {
192
+ integrations: [mdx({
193
+ rehypePlugins: [rehypeMinifyHtml],
194
+ })],
195
+ }
196
+ ```
197
+ </details>
198
+
199
+ <details>
200
+ <summary><strong>frontmatterOptions</strong></summary>
201
+
202
+ **Default:** `{ name: 'frontmatter' }`
203
+
204
+ We use [remark-mdx-frontmatter](https://github.com/remcohaszing/remark-mdx-frontmatter) to parse YAML-based frontmatter in your MDX files. If you want to override our default configuration or extend remark-mdx-frontmatter (ex. to [apply a custom frontmatter parser](https://github.com/remcohaszing/remark-mdx-frontmatter#parsers)), you can supply a `frontmatterOptions` configuration.
205
+
206
+ For example, say you want to access frontmatter as root-level variables without a nested `frontmatter` object. You can override the [`name` configuration option](https://github.com/remcohaszing/remark-mdx-frontmatter#name) like so:
207
+
208
+ ```js
209
+ // astro.config.mjs
210
+ export default {
211
+ integrations: [mdx({
212
+ frontmatterOptions: {
213
+ name: '',
214
+ }
215
+ })],
216
+ }
217
+ ```
218
+
219
+ ```mdx
220
+ ---
221
+ title: I'm just a variable now!
222
+ ---
223
+
224
+ # {title}
225
+ ```
226
+
227
+ See the [remark-mdx-frontmatter README](https://github.com/remcohaszing/remark-mdx-frontmatter#options) for a complete list of options.
228
+ </details>
229
+
230
+ ## Examples
231
+
232
+ - The [Astro MDX example](https://github.com/withastro/astro/tree/latest/examples/with-mdx) shows how to use MDX files in your Astro project.
233
+
234
+ ## Troubleshooting
235
+
236
+ For help, check out the `#support-threads` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
237
+
238
+ You can also check our [Astro Integration Documentation][astro-integration] for more on integrations.
239
+
240
+ ## Contributing
241
+
242
+ This package is maintained by Astro's Core team. You're welcome to submit an issue or PR!
243
+
244
+ ## Changelog
245
+
246
+ See [CHANGELOG.md](CHANGELOG.md) for a history of changes to this integration.
247
+
248
+ [astro-integration]: https://docs.astro.build/en/guides/integrations-guide/
249
+ [astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components
@@ -0,0 +1,18 @@
1
+ import { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
2
+ import type { AstroIntegration } from 'astro';
3
+ import type { RemarkMdxFrontmatterOptions } from 'remark-mdx-frontmatter';
4
+ declare type WithExtends<T> = T | {
5
+ extends: T;
6
+ };
7
+ declare type MdxOptions = {
8
+ remarkPlugins?: WithExtends<MdxRollupPluginOptions['remarkPlugins']>;
9
+ rehypePlugins?: WithExtends<MdxRollupPluginOptions['rehypePlugins']>;
10
+ /**
11
+ * Configure the remark-mdx-frontmatter plugin
12
+ * @see https://github.com/remcohaszing/remark-mdx-frontmatter#options for a full list of options
13
+ * @default {{ name: 'frontmatter' }}
14
+ */
15
+ frontmatterOptions?: RemarkMdxFrontmatterOptions;
16
+ };
17
+ export default function mdx(mdxOptions?: MdxOptions): AstroIntegration;
18
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,73 @@
1
+ import mdxPlugin from "@mdx-js/rollup";
2
+ import { parse as parseESM } from "es-module-lexer";
3
+ import remarkFrontmatter from "remark-frontmatter";
4
+ import remarkGfm from "remark-gfm";
5
+ import remarkMdxFrontmatter from "remark-mdx-frontmatter";
6
+ import remarkSmartypants from "remark-smartypants";
7
+ import { getFileInfo } from "./utils.js";
8
+ const DEFAULT_REMARK_PLUGINS = [remarkGfm, remarkSmartypants];
9
+ function handleExtends(config, defaults = []) {
10
+ if (Array.isArray(config))
11
+ return config;
12
+ return [...defaults, ...(config == null ? void 0 : config.extends) ?? []];
13
+ }
14
+ function mdx(mdxOptions = {}) {
15
+ return {
16
+ name: "@astrojs/mdx",
17
+ hooks: {
18
+ "astro:config:setup": ({ updateConfig, config, addPageExtension, command }) => {
19
+ addPageExtension(".mdx");
20
+ updateConfig({
21
+ vite: {
22
+ plugins: [
23
+ {
24
+ enforce: "pre",
25
+ ...mdxPlugin({
26
+ remarkPlugins: [
27
+ ...handleExtends(mdxOptions.remarkPlugins, DEFAULT_REMARK_PLUGINS),
28
+ remarkFrontmatter,
29
+ [
30
+ remarkMdxFrontmatter,
31
+ {
32
+ name: "frontmatter",
33
+ ...mdxOptions.frontmatterOptions
34
+ }
35
+ ]
36
+ ],
37
+ rehypePlugins: handleExtends(mdxOptions.rehypePlugins),
38
+ jsx: true,
39
+ jsxImportSource: "astro",
40
+ format: "mdx",
41
+ mdExtensions: []
42
+ })
43
+ },
44
+ {
45
+ name: "@astrojs/mdx",
46
+ transform(code, id) {
47
+ if (!id.endsWith(".mdx"))
48
+ return;
49
+ const [, moduleExports] = parseESM(code);
50
+ if (!moduleExports.includes("url")) {
51
+ const { fileUrl } = getFileInfo(id, config);
52
+ code += `
53
+ export const url = ${JSON.stringify(fileUrl)};`;
54
+ }
55
+ if (command === "dev") {
56
+ code += `
57
+ if (import.meta.hot) {
58
+ import.meta.hot.decline();
59
+ }`;
60
+ }
61
+ return code;
62
+ }
63
+ }
64
+ ]
65
+ }
66
+ });
67
+ }
68
+ }
69
+ };
70
+ }
71
+ export {
72
+ mdx as default
73
+ };
@@ -0,0 +1,6 @@
1
+ import type { AstroConfig } from 'astro';
2
+ /** @see 'vite-plugin-utils' for source */
3
+ export declare function getFileInfo(id: string, config: AstroConfig): {
4
+ fileId: string;
5
+ fileUrl: string | undefined;
6
+ };
package/dist/utils.js ADDED
@@ -0,0 +1,15 @@
1
+ function appendForwardSlash(path) {
2
+ return path.endsWith("/") ? path : path + "/";
3
+ }
4
+ function getFileInfo(id, config) {
5
+ const sitePathname = appendForwardSlash(config.site ? new URL(config.base, config.site).pathname : config.base);
6
+ const fileId = id.split("?")[0];
7
+ let fileUrl = fileId.includes("/pages/") ? fileId.replace(/^.*?\/pages\//, sitePathname).replace(/(\/index)?\.mdx$/, "") : void 0;
8
+ if (fileUrl && config.trailingSlash === "always") {
9
+ fileUrl = appendForwardSlash(fileUrl);
10
+ }
11
+ return { fileId, fileUrl };
12
+ }
13
+ export {
14
+ getFileInfo
15
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@astrojs/mdx",
3
+ "description": "Use MDX within Astro",
4
+ "version": "0.0.0-rc-20220721064837",
5
+ "type": "module",
6
+ "types": "./dist/index.d.ts",
7
+ "author": "withastro",
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/withastro/astro.git",
12
+ "directory": "packages/integrations/mdx"
13
+ },
14
+ "keywords": [
15
+ "astro-integration",
16
+ "astro-component",
17
+ "renderer",
18
+ "mdx"
19
+ ],
20
+ "bugs": "https://github.com/withastro/astro/issues",
21
+ "homepage": "https://docs.astro.build/en/guides/integrations-guide/mdx/",
22
+ "exports": {
23
+ ".": "./dist/index.js",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "dependencies": {
27
+ "@mdx-js/rollup": "^2.1.1",
28
+ "es-module-lexer": "^0.10.5",
29
+ "remark-frontmatter": "^4.0.1",
30
+ "remark-gfm": "^3.0.1",
31
+ "remark-mdx-frontmatter": "^2.0.2",
32
+ "remark-smartypants": "^2.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/chai": "^4.3.1",
36
+ "@types/mocha": "^9.1.1",
37
+ "@types/yargs-parser": "^21.0.0",
38
+ "astro": "0.0.0-rc-20220721064837",
39
+ "astro-scripts": "0.0.6",
40
+ "chai": "^4.3.6",
41
+ "linkedom": "^0.14.12",
42
+ "mocha": "^9.2.2",
43
+ "remark-toc": "^8.0.1"
44
+ },
45
+ "engines": {
46
+ "node": "^14.18.0 || >=16.12.0"
47
+ },
48
+ "scripts": {
49
+ "build": "astro-scripts build \"src/**/*.ts\" && tsc",
50
+ "build:ci": "astro-scripts build \"src/**/*.ts\"",
51
+ "dev": "astro-scripts dev \"src/**/*.ts\"",
52
+ "test": "mocha --exit --timeout 20000"
53
+ }
54
+ }
package/src/index.ts ADDED
@@ -0,0 +1,91 @@
1
+ import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
2
+ import type { AstroIntegration } from 'astro';
3
+ import { parse as parseESM } from 'es-module-lexer';
4
+ import remarkFrontmatter from 'remark-frontmatter';
5
+ import remarkGfm from 'remark-gfm';
6
+ import type { RemarkMdxFrontmatterOptions } from 'remark-mdx-frontmatter';
7
+ import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
8
+ import remarkSmartypants from 'remark-smartypants';
9
+ import { getFileInfo } from './utils.js';
10
+
11
+ type WithExtends<T> = T | { extends: T };
12
+
13
+ type MdxOptions = {
14
+ remarkPlugins?: WithExtends<MdxRollupPluginOptions['remarkPlugins']>;
15
+ rehypePlugins?: WithExtends<MdxRollupPluginOptions['rehypePlugins']>;
16
+ /**
17
+ * Configure the remark-mdx-frontmatter plugin
18
+ * @see https://github.com/remcohaszing/remark-mdx-frontmatter#options for a full list of options
19
+ * @default {{ name: 'frontmatter' }}
20
+ */
21
+ frontmatterOptions?: RemarkMdxFrontmatterOptions;
22
+ };
23
+
24
+ const DEFAULT_REMARK_PLUGINS = [remarkGfm, remarkSmartypants];
25
+
26
+ function handleExtends<T>(config: WithExtends<T[] | undefined>, defaults: T[] = []): T[] {
27
+ if (Array.isArray(config)) return config;
28
+
29
+ return [...defaults, ...(config?.extends ?? [])];
30
+ }
31
+
32
+ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
33
+ return {
34
+ name: '@astrojs/mdx',
35
+ hooks: {
36
+ 'astro:config:setup': ({ updateConfig, config, addPageExtension, command }: any) => {
37
+ addPageExtension('.mdx');
38
+ updateConfig({
39
+ vite: {
40
+ plugins: [
41
+ {
42
+ enforce: 'pre',
43
+ ...mdxPlugin({
44
+ remarkPlugins: [
45
+ ...handleExtends(mdxOptions.remarkPlugins, DEFAULT_REMARK_PLUGINS),
46
+ // Frontmatter plugins should always be applied!
47
+ // We can revisit this if a strong use case to *remove*
48
+ // YAML frontmatter via config is reported.
49
+ remarkFrontmatter,
50
+ [
51
+ remarkMdxFrontmatter,
52
+ {
53
+ name: 'frontmatter',
54
+ ...mdxOptions.frontmatterOptions,
55
+ },
56
+ ],
57
+ ],
58
+ rehypePlugins: handleExtends(mdxOptions.rehypePlugins),
59
+ jsx: true,
60
+ jsxImportSource: 'astro',
61
+ // Note: disable `.md` support
62
+ format: 'mdx',
63
+ mdExtensions: [],
64
+ }),
65
+ },
66
+ {
67
+ name: '@astrojs/mdx',
68
+ transform(code: string, id: string) {
69
+ if (!id.endsWith('.mdx')) return;
70
+ const [, moduleExports] = parseESM(code);
71
+
72
+ if (!moduleExports.includes('url')) {
73
+ const { fileUrl } = getFileInfo(id, config);
74
+ code += `\nexport const url = ${JSON.stringify(fileUrl)};`;
75
+ }
76
+ if (command === 'dev') {
77
+ // TODO: decline HMR updates until we have a stable approach
78
+ code += `\nif (import.meta.hot) {
79
+ import.meta.hot.decline();
80
+ }`;
81
+ }
82
+ return code;
83
+ },
84
+ },
85
+ ],
86
+ },
87
+ });
88
+ },
89
+ },
90
+ };
91
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { AstroConfig } from 'astro';
2
+
3
+ function appendForwardSlash(path: string) {
4
+ return path.endsWith('/') ? path : path + '/';
5
+ }
6
+
7
+ /** @see 'vite-plugin-utils' for source */
8
+ export function getFileInfo(id: string, config: AstroConfig) {
9
+ const sitePathname = appendForwardSlash(
10
+ config.site ? new URL(config.base, config.site).pathname : config.base
11
+ );
12
+
13
+ const fileId = id.split('?')[0];
14
+ let fileUrl = fileId.includes('/pages/')
15
+ ? fileId.replace(/^.*?\/pages\//, sitePathname).replace(/(\/index)?\.mdx$/, '')
16
+ : undefined;
17
+ if (fileUrl && config.trailingSlash === 'always') {
18
+ fileUrl = appendForwardSlash(fileUrl);
19
+ }
20
+ return { fileId, fileUrl };
21
+ }
@@ -0,0 +1,3 @@
1
+ # Hello component!
2
+
3
+ <div id="foo">bar</div>
@@ -0,0 +1,5 @@
1
+ ---
2
+ import Test from '../components/Test.mdx';
3
+ ---
4
+
5
+ <Test />
@@ -0,0 +1,9 @@
1
+ export async function get() {
2
+ const mdxPages = await import.meta.glob('./*.mdx', { eager: true });
3
+
4
+ return {
5
+ body: JSON.stringify({
6
+ titles: Object.values(mdxPages ?? {}).map(v => v?.customFrontmatter?.title),
7
+ })
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: 'Using YAML frontmatter'
3
+ illThrowIfIDontExist: "Oh no, that's scary!"
4
+ ---
5
+
6
+ # {customFrontmatter.illThrowIfIDontExist}
@@ -0,0 +1,9 @@
1
+ export async function get() {
2
+ const mdxPages = await import.meta.glob('./*.mdx', { eager: true });
3
+
4
+ return {
5
+ body: JSON.stringify({
6
+ titles: Object.values(mdxPages ?? {}).map(v => v?.frontmatter?.title),
7
+ })
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ title: 'Using YAML frontmatter'
3
+ illThrowIfIDontExist: "Oh no, that's scary!"
4
+ ---
5
+
6
+ # {frontmatter.illThrowIfIDontExist}
@@ -0,0 +1 @@
1
+ # Hello page!
@@ -0,0 +1,3 @@
1
+ # GitHub-flavored Markdown test
2
+
3
+ This should auto-gen a link: https://example.com
@@ -0,0 +1,19 @@
1
+ # TOC test
2
+
3
+ ## Table of contents
4
+
5
+ ## Section 1
6
+
7
+ Some text!
8
+
9
+ ### Subsection 1
10
+
11
+ Some subsection test!
12
+
13
+ ### Subsection 2
14
+
15
+ Oh cool, more text!
16
+
17
+ ## Section 2
18
+
19
+ And section 2, with a hyperlink to check GFM is preserved: https://handle-me-gfm.com
@@ -0,0 +1,9 @@
1
+ export async function get() {
2
+ const mdxPages = await import.meta.glob('./*.mdx', { eager: true });
3
+
4
+ return {
5
+ body: JSON.stringify({
6
+ urls: Object.values(mdxPages ?? {}).map(v => v?.url),
7
+ })
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ # I'm a page with a url of "/test-1!"
@@ -0,0 +1 @@
1
+ # I'm a page with a url of "/test-2!"
@@ -0,0 +1,3 @@
1
+ export const url = '/AH!'
2
+
3
+ # I'm a test with a url override!
@@ -0,0 +1,60 @@
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 Component', () => {
8
+ let fixture;
9
+
10
+ before(async () => {
11
+ fixture = await loadFixture({
12
+ root: new URL('./fixtures/mdx-component/', import.meta.url),
13
+ integrations: [mdx()],
14
+ });
15
+ });
16
+
17
+ describe('build', () => {
18
+ before(async () => {
19
+ await fixture.build();
20
+ });
21
+
22
+ it('works', async () => {
23
+ const html = await fixture.readFile('/index.html');
24
+ const { document } = parseHTML(html);
25
+
26
+ const h1 = document.querySelector('h1');
27
+ const foo = document.querySelector('#foo');
28
+
29
+ expect(h1.textContent).to.equal('Hello component!');
30
+ expect(foo.textContent).to.equal('bar');
31
+ });
32
+ });
33
+
34
+ describe('dev', () => {
35
+ let devServer;
36
+
37
+ before(async () => {
38
+ devServer = await fixture.startDevServer();
39
+ });
40
+
41
+ after(async () => {
42
+ await devServer.stop();
43
+ });
44
+
45
+ it('works', async () => {
46
+ const res = await fixture.fetch('/');
47
+
48
+ expect(res.status).to.equal(200);
49
+
50
+ const html = await res.text();
51
+ const { document } = parseHTML(html);
52
+
53
+ const h1 = document.querySelector('h1');
54
+ const foo = document.querySelector('#foo');
55
+
56
+ expect(h1.textContent).to.equal('Hello component!');
57
+ expect(foo.textContent).to.equal('bar');
58
+ });
59
+ });
60
+ });
@@ -0,0 +1,45 @@
1
+ import mdx from '@astrojs/mdx';
2
+
3
+ import { expect } from 'chai';
4
+ import { loadFixture } from '../../../astro/test/test-utils.js';
5
+
6
+ const FIXTURE_ROOT = new URL('./fixtures/mdx-frontmatter/', import.meta.url);
7
+
8
+ describe('MDX frontmatter', () => {
9
+ it('builds when "frontmatter.property" is in JSX expression', async () => {
10
+ const fixture = await loadFixture({
11
+ root: FIXTURE_ROOT,
12
+ integrations: [mdx()],
13
+ });
14
+ await fixture.build();
15
+ expect(true).to.equal(true);
16
+ });
17
+
18
+ it('extracts frontmatter to "frontmatter" export', async () => {
19
+ const fixture = await loadFixture({
20
+ root: FIXTURE_ROOT,
21
+ integrations: [mdx()],
22
+ });
23
+ await fixture.build();
24
+
25
+ const { titles } = JSON.parse(await fixture.readFile('/glob.json'));
26
+ expect(titles).to.include('Using YAML frontmatter');
27
+ });
28
+
29
+ it('extracts frontmatter to "customFrontmatter" export when configured', async () => {
30
+ const fixture = await loadFixture({
31
+ root: new URL('./fixtures/mdx-custom-frontmatter-name/', import.meta.url),
32
+ integrations: [
33
+ mdx({
34
+ frontmatterOptions: {
35
+ name: 'customFrontmatter',
36
+ },
37
+ }),
38
+ ],
39
+ });
40
+ await fixture.build();
41
+
42
+ const { titles } = JSON.parse(await fixture.readFile('/glob.json'));
43
+ expect(titles).to.include('Using YAML frontmatter');
44
+ });
45
+ });
@@ -0,0 +1,56 @@
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 Page', () => {
8
+ let fixture;
9
+
10
+ before(async () => {
11
+ fixture = await loadFixture({
12
+ root: new URL('./fixtures/mdx-page/', import.meta.url),
13
+ integrations: [mdx()],
14
+ });
15
+ });
16
+
17
+ describe('build', () => {
18
+ before(async () => {
19
+ await fixture.build();
20
+ });
21
+
22
+ it('works', async () => {
23
+ const html = await fixture.readFile('/index.html');
24
+ const { document } = parseHTML(html);
25
+
26
+ const h1 = document.querySelector('h1');
27
+
28
+ expect(h1.textContent).to.equal('Hello page!');
29
+ });
30
+ });
31
+
32
+ describe('dev', () => {
33
+ let devServer;
34
+
35
+ before(async () => {
36
+ devServer = await fixture.startDevServer();
37
+ });
38
+
39
+ after(async () => {
40
+ await devServer.stop();
41
+ });
42
+
43
+ it('works', async () => {
44
+ const res = await fixture.fetch('/');
45
+
46
+ expect(res.status).to.equal(200);
47
+
48
+ const html = await res.text();
49
+ const { document } = parseHTML(html);
50
+
51
+ const h1 = document.querySelector('h1');
52
+
53
+ expect(h1.textContent).to.equal('Hello page!');
54
+ });
55
+ });
56
+ });
@@ -0,0 +1,62 @@
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
+ import remarkToc from 'remark-toc';
7
+
8
+ const FIXTURE_ROOT = new URL('./fixtures/mdx-remark-plugins/', import.meta.url);
9
+
10
+ describe('MDX remark plugins', () => {
11
+ it('supports custom remark plugins - TOC', async () => {
12
+ const fixture = await loadFixture({
13
+ root: FIXTURE_ROOT,
14
+ integrations: [
15
+ mdx({
16
+ remarkPlugins: [remarkToc],
17
+ }),
18
+ ],
19
+ });
20
+ await fixture.build();
21
+
22
+ const html = await fixture.readFile('/with-toc/index.html');
23
+ const { document } = parseHTML(html);
24
+
25
+ const tocLink1 = document.querySelector('ul a[href="#section-1"]');
26
+ expect(tocLink1).to.not.be.null;
27
+ });
28
+
29
+ it('applies GitHub-flavored markdown by default', async () => {
30
+ const fixture = await loadFixture({
31
+ root: FIXTURE_ROOT,
32
+ integrations: [mdx()],
33
+ });
34
+ await fixture.build();
35
+
36
+ const html = await fixture.readFile('/with-gfm/index.html');
37
+ const { document } = parseHTML(html);
38
+
39
+ const autoGenLink = document.querySelector('a[href="https://example.com"]');
40
+ expect(autoGenLink).to.not.be.null;
41
+ });
42
+
43
+ it('preserves default GitHub-flavored markdown with "extends"', async () => {
44
+ const fixture = await loadFixture({
45
+ root: FIXTURE_ROOT,
46
+ integrations: [
47
+ mdx({
48
+ remarkPlugins: { extends: [remarkToc] },
49
+ }),
50
+ ],
51
+ });
52
+ await fixture.build();
53
+
54
+ const html = await fixture.readFile('/with-toc/index.html');
55
+ const { document } = parseHTML(html);
56
+
57
+ const tocLink1 = document.querySelector('ul a[href="#section-1"]');
58
+ expect(tocLink1).to.not.be.null;
59
+ const autoGenLink = document.querySelector('a[href="https://handle-me-gfm.com"]');
60
+ expect(autoGenLink).to.not.be.null;
61
+ });
62
+ });
@@ -0,0 +1,28 @@
1
+ import mdx from '@astrojs/mdx';
2
+
3
+ import { expect } from 'chai';
4
+ import { loadFixture } from '../../../astro/test/test-utils.js';
5
+
6
+ describe('MDX url export', () => {
7
+ let fixture;
8
+
9
+ before(async () => {
10
+ fixture = await loadFixture({
11
+ root: new URL('./fixtures/mdx-url-export/', import.meta.url),
12
+ integrations: [mdx()],
13
+ });
14
+
15
+ await fixture.build();
16
+ });
17
+
18
+ it('generates correct urls in glob result', async () => {
19
+ const { urls } = JSON.parse(await fixture.readFile('/pages.json'));
20
+ expect(urls).to.include('/test-1');
21
+ expect(urls).to.include('/test-2');
22
+ });
23
+
24
+ it('respects "export url" overrides in glob result', async () => {
25
+ const { urls } = JSON.parse(await fixture.readFile('/pages.json'));
26
+ expect(urls).to.include('/AH!');
27
+ });
28
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "include": ["src"],
4
+ "compilerOptions": {
5
+ "allowJs": true,
6
+ "module": "ES2020",
7
+ "outDir": "./dist",
8
+ "target": "ES2020"
9
+ }
10
+ }