diff options
Diffstat (limited to 'packages/integrations/mdx/src')
-rw-r--r-- | packages/integrations/mdx/src/index.ts | 48 | ||||
-rw-r--r-- | packages/integrations/mdx/src/utils.ts | 23 |
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; + } + } +} |