UNPKG

@astrojs/mdx

Version:

Add support for MDX pages in your Astro site

94 lines (93 loc) 3.2 kB
import { parse } from "es-module-lexer"; import { ASTRO_IMAGE_ELEMENT, ASTRO_IMAGE_IMPORT, USES_ASTRO_IMAGE_FLAG } from "./rehype-images-to-component.js"; import { getFileInfo } from "./utils.js"; const underscoreFragmentImportRegex = /[\s,{]_Fragment[\s,}]/; const astroTagComponentImportRegex = /[\s,{]__astro_tag_component__[\s,}]/; function vitePluginMdxPostprocess(astroConfig) { return { name: "@astrojs/mdx-postprocess", transform(code, id, opts) { if (!id.endsWith(".mdx")) return; const fileInfo = getFileInfo(id, astroConfig); const [imports, exports] = parse(code); code = injectUnderscoreFragmentImport(code, imports); code = injectMetadataExports(code, exports, fileInfo); code = transformContentExport(code, exports); code = annotateContentExport(code, id, !!opts?.ssr, imports); return { code, map: null }; } }; } function injectUnderscoreFragmentImport(code, imports) { if (!isSpecifierImported(code, imports, underscoreFragmentImportRegex, "astro/jsx-runtime")) { code += ` import { Fragment as _Fragment } from 'astro/jsx-runtime';`; } return code; } function injectMetadataExports(code, exports, fileInfo) { if (!exports.some(({ n }) => n === "url")) { code += ` export const url = ${JSON.stringify(fileInfo.fileUrl)};`; } if (!exports.some(({ n }) => n === "file")) { code += ` export const file = ${JSON.stringify(fileInfo.fileId)};`; } return code; } function transformContentExport(code, exports) { if (exports.find(({ n }) => n === "Content")) return code; const hasComponents = exports.find(({ n }) => n === "components"); const usesAstroImage = exports.find(({ n }) => n === USES_ASTRO_IMAGE_FLAG); let componentsCode = `{ Fragment: _Fragment${hasComponents ? ", ...components" : ""}, ...props.components,`; if (usesAstroImage) { componentsCode += ` ${JSON.stringify(ASTRO_IMAGE_ELEMENT)}: ${hasComponents ? "components.img ?? " : ""} props.components?.img ?? ${ASTRO_IMAGE_IMPORT}`; } componentsCode += " }"; code = code.replace("export default function MDXContent", "function MDXContent"); code += ` export const Content = (props = {}) => MDXContent({ ...props, components: ${componentsCode}, }); export default Content;`; return code; } function annotateContentExport(code, id, ssr, imports) { code += ` Content[Symbol.for('mdx-component')] = true`; code += ` Content[Symbol.for('astro.needsHeadRendering')] = !Boolean(frontmatter.layout);`; code += ` Content.moduleId = ${JSON.stringify(id)};`; if (ssr) { if (!isSpecifierImported( code, imports, astroTagComponentImportRegex, "astro/runtime/server/index.js" )) { code += ` import { __astro_tag_component__ } from 'astro/runtime/server/index.js';`; } code += ` __astro_tag_component__(Content, 'astro:jsx');`; } return code; } function isSpecifierImported(code, imports, specifierRegex, source) { for (const imp of imports) { if (imp.n !== source) continue; const importStatement = code.slice(imp.ss, imp.se); if (specifierRegex.test(importStatement)) return true; } return false; } export { vitePluginMdxPostprocess };