@astrojs/mdx 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,15 +42,16 @@ npm install @astrojs/mdx
42
42
 
43
43
  Then, apply this integration to your `astro.config.*` file using the `integrations` property:
44
44
 
45
- ```js ins={3} "mdx()"
46
- // astro.config.mjs
47
- import { defineConfig } from 'astro/config';
48
- import mdx from '@astrojs/mdx';
49
-
50
- export default defineConfig({
51
- // ...
52
- integrations: [mdx()],
53
- });
45
+ ```diff lang="js" "mdx()"
46
+ // astro.config.mjs
47
+ import { defineConfig } from 'astro/config';
48
+ + import mdx from '@astrojs/mdx';
49
+
50
+ export default defineConfig({
51
+ // ...
52
+ integrations: [mdx()],
53
+ // ^^^^^
54
+ });
54
55
  ```
55
56
 
56
57
  ### Editor Integration
package/dist/index.js CHANGED
@@ -1,13 +1,15 @@
1
- import { markdownConfigDefaults } from "@astrojs/markdown-remark";
2
- import { toRemarkInitializeAstroData } from "@astrojs/markdown-remark/dist/internal.js";
3
- import { compile as mdxCompile } from "@mdx-js/mdx";
1
+ import { markdownConfigDefaults, setVfileFrontmatter } from "@astrojs/markdown-remark";
4
2
  import astroJSXRenderer from "astro/jsx/renderer.js";
5
3
  import { parse as parseESM } from "es-module-lexer";
6
4
  import fs from "node:fs/promises";
7
5
  import { fileURLToPath } from "node:url";
8
- import { SourceMapGenerator } from "source-map";
9
6
  import { VFile } from "vfile";
10
- import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from "./plugins.js";
7
+ import { createMdxProcessor } from "./plugins.js";
8
+ import {
9
+ ASTRO_IMAGE_ELEMENT,
10
+ ASTRO_IMAGE_IMPORT,
11
+ USES_ASTRO_IMAGE_FLAG
12
+ } from "./remark-images-to-component.js";
11
13
  import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from "./utils.js";
12
14
  function mdx(partialMdxOptions = {}) {
13
15
  return {
@@ -50,20 +52,7 @@ function mdx(partialMdxOptions = {}) {
50
52
  extendMarkdownConfig ? config.markdown : markdownConfigDefaults
51
53
  )
52
54
  });
53
- const mdxPluginOpts = {
54
- remarkPlugins: await getRemarkPlugins(mdxOptions),
55
- rehypePlugins: getRehypePlugins(mdxOptions),
56
- recmaPlugins: mdxOptions.recmaPlugins,
57
- remarkRehypeOptions: mdxOptions.remarkRehype,
58
- jsx: true,
59
- jsxImportSource: "astro",
60
- // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
61
- format: "mdx",
62
- mdExtensions: []
63
- };
64
- let importMetaEnv = {
65
- SITE: config.site
66
- };
55
+ let processor;
67
56
  updateConfig({
68
57
  vite: {
69
58
  plugins: [
@@ -71,7 +60,10 @@ function mdx(partialMdxOptions = {}) {
71
60
  name: "@mdx-js/rollup",
72
61
  enforce: "pre",
73
62
  configResolved(resolved) {
74
- importMetaEnv = { ...importMetaEnv, ...resolved.env };
63
+ processor = createMdxProcessor(mdxOptions, {
64
+ sourcemap: !!resolved.build.sourcemap,
65
+ importMetaEnv: { SITE: config.site, ...resolved.env }
66
+ });
75
67
  const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === "astro:jsx");
76
68
  if (jsxPluginIndex !== -1) {
77
69
  const myPluginIndex = resolved.plugins.findIndex(
@@ -92,21 +84,10 @@ function mdx(partialMdxOptions = {}) {
92
84
  const { fileId } = getFileInfo(id, config);
93
85
  const code = await fs.readFile(fileId, "utf-8");
94
86
  const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
87
+ const vfile = new VFile({ value: pageContent, path: id });
88
+ setVfileFrontmatter(vfile, frontmatter);
95
89
  try {
96
- const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
97
- ...mdxPluginOpts,
98
- elementAttributeNameCase: "html",
99
- remarkPlugins: [
100
- // Ensure `data.astro` is available to all remark plugins
101
- toRemarkInitializeAstroData({ userFrontmatter: frontmatter }),
102
- ...mdxPluginOpts.remarkPlugins ?? []
103
- ],
104
- recmaPlugins: [
105
- ...mdxPluginOpts.recmaPlugins ?? [],
106
- () => recmaInjectImportMetaEnvPlugin({ importMetaEnv })
107
- ],
108
- SourceMapGenerator: config.vite.build?.sourcemap ? SourceMapGenerator : void 0
109
- });
90
+ const compiled = await processor.process(vfile);
110
91
  return {
111
92
  code: escapeViteEnvReferences(String(compiled.value)),
112
93
  map: compiled.map
@@ -145,11 +126,19 @@ export const file = ${JSON.stringify(fileId)};`;
145
126
  }
146
127
  if (!moduleExports.find(({ n }) => n === "Content")) {
147
128
  const hasComponents = moduleExports.find(({ n }) => n === "components");
129
+ const usesAstroImage = moduleExports.find(
130
+ ({ n }) => n === USES_ASTRO_IMAGE_FLAG
131
+ );
132
+ let componentsCode = `{ Fragment${hasComponents ? ", ...components" : ""}, ...props.components,`;
133
+ if (usesAstroImage) {
134
+ componentsCode += ` ${JSON.stringify(ASTRO_IMAGE_ELEMENT)}: ${hasComponents ? "components.img ?? " : ""} props.components?.img ?? ${ASTRO_IMAGE_IMPORT}`;
135
+ }
136
+ componentsCode += " }";
148
137
  code = code.replace("export default MDXContent;", "");
149
138
  code += `
150
139
  export const Content = (props = {}) => MDXContent({
151
140
  ...props,
152
- components: { Fragment${hasComponents ? ", ...components" : ""}, ...props.components },
141
+ components: ${componentsCode},
153
142
  });
154
143
  export default Content;`;
155
144
  }
package/dist/plugins.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
2
- import type { VFile } from 'vfile';
1
+ import type { Processor } from 'unified';
3
2
  import type { MdxOptions } from './index.js';
4
- export declare function recmaInjectImportMetaEnvPlugin({ importMetaEnv, }: {
3
+ interface MdxProcessorExtraOptions {
4
+ sourcemap: boolean;
5
5
  importMetaEnv: Record<string, any>;
6
- }): (tree: any) => void;
7
- export declare function rehypeApplyFrontmatterExport(): (tree: any, vfile: VFile) => void;
8
- export declare function getRemarkPlugins(mdxOptions: MdxOptions): Promise<PluggableList>;
9
- export declare function getRehypePlugins(mdxOptions: MdxOptions): PluggableList;
6
+ }
7
+ export declare function createMdxProcessor(mdxOptions: MdxOptions, extraOptions: MdxProcessorExtraOptions): Processor;
8
+ export {};
package/dist/plugins.js CHANGED
@@ -4,84 +4,34 @@ import {
4
4
  remarkPrism,
5
5
  remarkShiki
6
6
  } from "@astrojs/markdown-remark";
7
- import {
8
- InvalidAstroDataError,
9
- safelyGetAstroData
10
- } from "@astrojs/markdown-remark/dist/internal.js";
11
- import { nodeTypes } from "@mdx-js/mdx";
12
- import { visit as estreeVisit } from "estree-util-visit";
7
+ import { createProcessor, nodeTypes } from "@mdx-js/mdx";
13
8
  import rehypeRaw from "rehype-raw";
14
9
  import remarkGfm from "remark-gfm";
15
10
  import remarkSmartypants from "remark-smartypants";
11
+ import { SourceMapGenerator } from "source-map";
12
+ import { recmaInjectImportMetaEnv } from "./recma-inject-import-meta-env.js";
13
+ import { rehypeApplyFrontmatterExport } from "./rehype-apply-frontmatter-export.js";
16
14
  import { rehypeInjectHeadingsExport } from "./rehype-collect-headings.js";
17
15
  import rehypeMetaString from "./rehype-meta-string.js";
18
16
  import { rehypeOptimizeStatic } from "./rehype-optimize-static.js";
19
17
  import { remarkImageToComponent } from "./remark-images-to-component.js";
20
- import { jsToTreeNode } from "./utils.js";
21
18
  const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
22
- function recmaInjectImportMetaEnvPlugin({
23
- importMetaEnv
24
- }) {
25
- return (tree) => {
26
- estreeVisit(tree, (node) => {
27
- if (node.type === "MemberExpression") {
28
- const envVarName = getImportMetaEnvVariableName(node);
29
- if (typeof envVarName === "string") {
30
- for (const key in node) {
31
- delete node[key];
32
- }
33
- const envVarLiteral = {
34
- type: "Literal",
35
- value: importMetaEnv[envVarName],
36
- raw: JSON.stringify(importMetaEnv[envVarName])
37
- };
38
- Object.assign(node, envVarLiteral);
39
- }
40
- }
41
- });
42
- };
43
- }
44
- function rehypeApplyFrontmatterExport() {
45
- return function(tree, vfile) {
46
- const astroData = safelyGetAstroData(vfile.data);
47
- if (astroData instanceof InvalidAstroDataError)
48
- throw new Error(
49
- // Copied from Astro core `errors-data`
50
- // TODO: find way to import error data from core
51
- '[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.'
52
- );
53
- const { frontmatter } = astroData;
54
- const exportNodes = [
55
- jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`)
56
- ];
57
- if (frontmatter.layout) {
58
- exportNodes.unshift(
59
- jsToTreeNode(
60
- /** @see 'vite-plugin-markdown' for layout props reference */
61
- `import { jsx as layoutJsx } from 'astro/jsx-runtime';
62
-
63
- export default async function ({ children }) {
64
- const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default;
65
- const { layout, ...content } = frontmatter;
66
- content.file = file;
67
- content.url = url;
68
- return layoutJsx(Layout, {
69
- file,
70
- url,
71
- content,
72
- frontmatter: content,
73
- headings: getHeadings(),
74
- 'server:root': true,
75
- children,
76
- });
77
- };`
78
- )
79
- );
80
- }
81
- tree.children = exportNodes.concat(tree.children);
82
- };
19
+ function createMdxProcessor(mdxOptions, extraOptions) {
20
+ return createProcessor({
21
+ remarkPlugins: getRemarkPlugins(mdxOptions),
22
+ rehypePlugins: getRehypePlugins(mdxOptions),
23
+ recmaPlugins: getRecmaPlugins(mdxOptions, extraOptions.importMetaEnv),
24
+ remarkRehypeOptions: mdxOptions.remarkRehype,
25
+ jsx: true,
26
+ jsxImportSource: "astro",
27
+ // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
28
+ format: "mdx",
29
+ mdExtensions: [],
30
+ elementAttributeNameCase: "html",
31
+ SourceMapGenerator: extraOptions.sourcemap ? SourceMapGenerator : void 0
32
+ });
83
33
  }
84
- async function getRemarkPlugins(mdxOptions) {
34
+ function getRemarkPlugins(mdxOptions) {
85
35
  let remarkPlugins = [remarkCollectImages, remarkImageToComponent];
86
36
  if (!isPerformanceBenchmark) {
87
37
  if (mdxOptions.gfm) {
@@ -124,29 +74,9 @@ function getRehypePlugins(mdxOptions) {
124
74
  }
125
75
  return rehypePlugins;
126
76
  }
127
- function getImportMetaEnvVariableName(node) {
128
- try {
129
- if (node.object.type !== "MemberExpression" || node.property.type !== "Identifier")
130
- return new Error();
131
- const nestedExpression = node.object;
132
- if (nestedExpression.property.type !== "Identifier" || nestedExpression.property.name !== "env")
133
- return new Error();
134
- const envExpression = nestedExpression.object;
135
- if (envExpression.type !== "MetaProperty" || envExpression.property.type !== "Identifier" || envExpression.property.name !== "meta")
136
- return new Error();
137
- if (envExpression.meta.name !== "import")
138
- return new Error();
139
- return node.property.name;
140
- } catch (e) {
141
- if (e instanceof Error) {
142
- return e;
143
- }
144
- return new Error("Unknown parsing error");
145
- }
77
+ function getRecmaPlugins(mdxOptions, importMetaEnv) {
78
+ return [...mdxOptions.recmaPlugins ?? [], [recmaInjectImportMetaEnv, { importMetaEnv }]];
146
79
  }
147
80
  export {
148
- getRehypePlugins,
149
- getRemarkPlugins,
150
- recmaInjectImportMetaEnvPlugin,
151
- rehypeApplyFrontmatterExport
81
+ createMdxProcessor
152
82
  };
@@ -0,0 +1,3 @@
1
+ export declare function recmaInjectImportMetaEnv({ importMetaEnv, }: {
2
+ importMetaEnv: Record<string, any>;
3
+ }): (tree: any) => void;
@@ -0,0 +1,46 @@
1
+ import { visit as estreeVisit } from "estree-util-visit";
2
+ function recmaInjectImportMetaEnv({
3
+ importMetaEnv
4
+ }) {
5
+ return (tree) => {
6
+ estreeVisit(tree, (node) => {
7
+ if (node.type === "MemberExpression") {
8
+ const envVarName = getImportMetaEnvVariableName(node);
9
+ if (typeof envVarName === "string") {
10
+ for (const key in node) {
11
+ delete node[key];
12
+ }
13
+ const envVarLiteral = {
14
+ type: "Literal",
15
+ value: importMetaEnv[envVarName],
16
+ raw: JSON.stringify(importMetaEnv[envVarName])
17
+ };
18
+ Object.assign(node, envVarLiteral);
19
+ }
20
+ }
21
+ });
22
+ };
23
+ }
24
+ function getImportMetaEnvVariableName(node) {
25
+ try {
26
+ if (node.object.type !== "MemberExpression" || node.property.type !== "Identifier")
27
+ return new Error();
28
+ const nestedExpression = node.object;
29
+ if (nestedExpression.property.type !== "Identifier" || nestedExpression.property.name !== "env")
30
+ return new Error();
31
+ const envExpression = nestedExpression.object;
32
+ if (envExpression.type !== "MetaProperty" || envExpression.property.type !== "Identifier" || envExpression.property.name !== "meta")
33
+ return new Error();
34
+ if (envExpression.meta.name !== "import")
35
+ return new Error();
36
+ return node.property.name;
37
+ } catch (e) {
38
+ if (e instanceof Error) {
39
+ return e;
40
+ }
41
+ return new Error("Unknown parsing error");
42
+ }
43
+ }
44
+ export {
45
+ recmaInjectImportMetaEnv
46
+ };
@@ -0,0 +1,2 @@
1
+ import type { VFile } from 'vfile';
2
+ export declare function rehypeApplyFrontmatterExport(): (tree: any, vfile: VFile) => void;
@@ -0,0 +1,46 @@
1
+ import { InvalidAstroDataError } from "@astrojs/markdown-remark";
2
+ import { safelyGetAstroData } from "@astrojs/markdown-remark/dist/internal.js";
3
+ import { jsToTreeNode } from "./utils.js";
4
+ function rehypeApplyFrontmatterExport() {
5
+ return function(tree, vfile) {
6
+ const astroData = safelyGetAstroData(vfile.data);
7
+ if (astroData instanceof InvalidAstroDataError)
8
+ throw new Error(
9
+ // Copied from Astro core `errors-data`
10
+ // TODO: find way to import error data from core
11
+ '[MDX] A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.'
12
+ );
13
+ const { frontmatter } = astroData;
14
+ const exportNodes = [
15
+ jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`)
16
+ ];
17
+ if (frontmatter.layout) {
18
+ exportNodes.unshift(
19
+ jsToTreeNode(
20
+ /** @see 'vite-plugin-markdown' for layout props reference */
21
+ `import { jsx as layoutJsx } from 'astro/jsx-runtime';
22
+
23
+ export default async function ({ children }) {
24
+ const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default;
25
+ const { layout, ...content } = frontmatter;
26
+ content.file = file;
27
+ content.url = url;
28
+ return layoutJsx(Layout, {
29
+ file,
30
+ url,
31
+ content,
32
+ frontmatter: content,
33
+ headings: getHeadings(),
34
+ 'server:root': true,
35
+ children,
36
+ });
37
+ };`
38
+ )
39
+ );
40
+ }
41
+ tree.children = exportNodes.concat(tree.children);
42
+ };
43
+ }
44
+ export {
45
+ rehypeApplyFrontmatterExport
46
+ };
@@ -1,2 +1,5 @@
1
1
  import type { MarkdownVFile } from '@astrojs/markdown-remark';
2
+ export declare const ASTRO_IMAGE_ELEMENT = "astro-image";
3
+ export declare const ASTRO_IMAGE_IMPORT = "__AstroImage__";
4
+ export declare const USES_ASTRO_IMAGE_FLAG = "__usesAstroImage";
2
5
  export declare function remarkImageToComponent(): (tree: any, file: MarkdownVFile) => void;
@@ -1,5 +1,8 @@
1
1
  import { visit } from "unist-util-visit";
2
2
  import { jsToTreeNode } from "./utils.js";
3
+ const ASTRO_IMAGE_ELEMENT = "astro-image";
4
+ const ASTRO_IMAGE_IMPORT = "__AstroImage__";
5
+ const USES_ASTRO_IMAGE_FLAG = "__usesAstroImage";
3
6
  function remarkImageToComponent() {
4
7
  return function(tree, file) {
5
8
  if (!file.data.imagePaths)
@@ -36,7 +39,7 @@ function remarkImageToComponent() {
36
39
  importedImages.set(node.url, importName);
37
40
  }
38
41
  const componentElement = {
39
- name: "__AstroImage__",
42
+ name: ASTRO_IMAGE_ELEMENT,
40
43
  type: "mdxJsxFlowElement",
41
44
  attributes: [
42
45
  {
@@ -75,9 +78,15 @@ function remarkImageToComponent() {
75
78
  }
76
79
  });
77
80
  tree.children.unshift(...importsStatements);
78
- tree.children.unshift(jsToTreeNode(`import { Image as __AstroImage__ } from "astro:assets";`));
81
+ tree.children.unshift(
82
+ jsToTreeNode(`import { Image as ${ASTRO_IMAGE_IMPORT} } from "astro:assets";`)
83
+ );
84
+ tree.children.push(jsToTreeNode(`export const ${USES_ASTRO_IMAGE_FLAG} = true`));
79
85
  };
80
86
  }
81
87
  export {
88
+ ASTRO_IMAGE_ELEMENT,
89
+ ASTRO_IMAGE_IMPORT,
90
+ USES_ASTRO_IMAGE_FLAG,
82
91
  remarkImageToComponent
83
92
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@astrojs/mdx",
3
3
  "description": "Add support for MDX pages in your Astro site",
4
- "version": "1.0.3",
4
+ "version": "1.1.1",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
7
7
  "author": "withastro",
@@ -41,10 +41,10 @@
41
41
  "source-map": "^0.7.4",
42
42
  "unist-util-visit": "^4.1.2",
43
43
  "vfile": "^5.3.7",
44
- "@astrojs/markdown-remark": "3.1.0"
44
+ "@astrojs/markdown-remark": "3.2.1"
45
45
  },
46
46
  "peerDependencies": {
47
- "astro": "^3.0.11"
47
+ "astro": "^3.2.3"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/chai": "^4.3.5",
@@ -65,13 +65,17 @@
65
65
  "remark-rehype": "^10.1.0",
66
66
  "remark-shiki-twoslash": "^3.1.3",
67
67
  "remark-toc": "^8.0.1",
68
+ "unified": "^10.1.2",
68
69
  "vite": "^4.4.9",
69
- "astro": "3.0.11",
70
+ "astro": "3.2.3",
70
71
  "astro-scripts": "0.0.14"
71
72
  },
72
73
  "engines": {
73
74
  "node": ">=18.14.1"
74
75
  },
76
+ "publishConfig": {
77
+ "provenance": true
78
+ },
75
79
  "scripts": {
76
80
  "build": "astro-scripts build \"src/**/*.ts\" && tsc",
77
81
  "build:ci": "astro-scripts build \"src/**/*.ts\"",