summaryrefslogtreecommitdiff
path: root/packages/integrations/mdx/src
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2022-07-29 10:22:57 -0500
committerGravatar GitHub <noreply@github.com> 2022-07-29 11:22:57 -0400
commit1743fe140eb58d60e26cbd11a066bb60de046e0c (patch)
treef3e4f24e2ad90c80df47add8a29406cf93217d1a /packages/integrations/mdx/src
parent45bec97d28d97edd5c234caf3ec97e1977bea0f7 (diff)
downloadastro-1743fe140eb58d60e26cbd11a066bb60de046e0c.tar.gz
astro-1743fe140eb58d60e26cbd11a066bb60de046e0c.tar.zst
astro-1743fe140eb58d60e26cbd11a066bb60de046e0c.zip
feat: support `layout` in MDX frontmatter (#4088)
* deps: add gray-matter * feat: support layout frontmatter property * test: frontmatter, content prop * docs: update layout recommendation * deps: fix lockfile * chore: changeset * fix: inherit rollup plugin transform * fix: avoid parsing frontmatter on custom parsers * fix: match YAML err handling from md * docs: absolute url to docs Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * chore: formatting Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
Diffstat (limited to 'packages/integrations/mdx/src')
-rw-r--r--packages/integrations/mdx/src/index.ts48
-rw-r--r--packages/integrations/mdx/src/utils.ts23
2 files changed, 58 insertions, 13 deletions
diff --git a/packages/integrations/mdx/src/index.ts b/packages/integrations/mdx/src/index.ts
index cb3f7c3fe..9313d10ee 100644
--- a/packages/integrations/mdx/src/index.ts
+++ b/packages/integrations/mdx/src/index.ts
@@ -1,3 +1,4 @@
+import type { Plugin as VitePlugin } from 'vite';
import { nodeTypes } from '@mdx-js/mdx';
import mdxPlugin, { Options as MdxRollupPluginOptions } from '@mdx-js/rollup';
import type { AstroIntegration } from 'astro';
@@ -10,7 +11,7 @@ import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
import remarkShikiTwoslash from 'remark-shiki-twoslash';
import remarkSmartypants from 'remark-smartypants';
import remarkPrism from './remark-prism.js';
-import { getFileInfo } from './utils.js';
+import { getFileInfo, getFrontmatter } from './utils.js';
type WithExtends<T> = T | { extends: T };
@@ -68,24 +69,47 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
},
]);
+ const configuredMdxPlugin = mdxPlugin({
+ remarkPlugins,
+ rehypePlugins,
+ jsx: true,
+ jsxImportSource: 'astro',
+ // Note: disable `.md` support
+ format: 'mdx',
+ mdExtensions: [],
+ })
+
updateConfig({
vite: {
plugins: [
{
enforce: 'pre',
- ...mdxPlugin({
- remarkPlugins,
- rehypePlugins,
- jsx: true,
- jsxImportSource: 'astro',
- // Note: disable `.md` support
- format: 'mdx',
- mdExtensions: [],
- }),
+ ...configuredMdxPlugin,
+ // Override transform to inject layouts before MDX compilation
+ async transform(this, code, id) {
+ if (!id.endsWith('.mdx')) return;
+
+ const mdxPluginTransform = configuredMdxPlugin.transform?.bind(this);
+ // If user overrides our default YAML parser,
+ // do not attempt to parse the `layout` via gray-matter
+ if (mdxOptions.frontmatterOptions?.parsers) {
+ return mdxPluginTransform?.(code, id);
+ }
+ const frontmatter = getFrontmatter(code, id);
+ if (frontmatter.layout) {
+ const { layout, ...content } = frontmatter;
+ code += `\nexport default async function({ children }) {\nconst Layout = (await import(${
+ JSON.stringify(frontmatter.layout)
+ })).default;\nreturn <Layout content={${
+ JSON.stringify(content)
+ }}>{children}</Layout> }`
+ }
+ return mdxPluginTransform?.(code, id);
+ }
},
{
name: '@astrojs/mdx',
- transform(code: string, id: string) {
+ transform(code, id) {
if (!id.endsWith('.mdx')) return;
const [, moduleExports] = parseESM(code);
@@ -113,7 +137,7 @@ export default function mdx(mdxOptions: MdxOptions = {}): AstroIntegration {
return code;
},
},
- ],
+ ] as VitePlugin[],
},
});
},
diff --git a/packages/integrations/mdx/src/utils.ts b/packages/integrations/mdx/src/utils.ts
index 6eb7a3570..97bc72d74 100644
--- a/packages/integrations/mdx/src/utils.ts
+++ b/packages/integrations/mdx/src/utils.ts
@@ -1,4 +1,5 @@
-import type { AstroConfig } from 'astro';
+import type { AstroConfig, SSRError } from 'astro';
+import matter from 'gray-matter';
function appendForwardSlash(path: string) {
return path.endsWith('/') ? path : path + '/';
@@ -37,3 +38,23 @@ export function getFileInfo(id: string, config: AstroConfig): FileInfo {
}
return { fileId, fileUrl };
}
+
+/**
+ * Match YAML exception handling from Astro core errors
+ * @see 'astro/src/core/errors.ts'
+ */
+export function getFrontmatter(code: string, id: string) {
+ try {
+ return matter(code).data;
+ } catch (e: any) {
+ if (e.name === 'YAMLException') {
+ const err: SSRError = e;
+ err.id = id;
+ err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
+ err.message = e.reason;
+ throw err;
+ } else {
+ throw e;
+ }
+ }
+}