summaryrefslogtreecommitdiff
path: root/packages/integrations/mdx/src/plugins.ts
diff options
context:
space:
mode:
authorGravatar Bjorn Lu <bjornlu.dev@gmail.com> 2023-09-14 20:05:38 +0800
committerGravatar GitHub <noreply@github.com> 2023-09-14 20:05:38 +0800
commit74dc3edb305c49feec49c39082fa836485da8a92 (patch)
treedd7b7584627f369c462c421892978658180287f1 /packages/integrations/mdx/src/plugins.ts
parent2e8726feec2e0d6ba8bd4db941009986e8e34141 (diff)
downloadastro-74dc3edb305c49feec49c39082fa836485da8a92.tar.gz
astro-74dc3edb305c49feec49c39082fa836485da8a92.tar.zst
astro-74dc3edb305c49feec49c39082fa836485da8a92.zip
Improve MDX rendering performance (#8533)
Diffstat (limited to 'packages/integrations/mdx/src/plugins.ts')
-rw-r--r--packages/integrations/mdx/src/plugins.ts143
1 files changed, 31 insertions, 112 deletions
diff --git a/packages/integrations/mdx/src/plugins.ts b/packages/integrations/mdx/src/plugins.ts
index a3d9e4ff3..3286a9fd8 100644
--- a/packages/integrations/mdx/src/plugins.ts
+++ b/packages/integrations/mdx/src/plugins.ts
@@ -4,101 +4,49 @@ import {
remarkPrism,
remarkShiki,
} from '@astrojs/markdown-remark';
-import {
- InvalidAstroDataError,
- safelyGetAstroData,
-} from '@astrojs/markdown-remark/dist/internal.js';
-import { nodeTypes } from '@mdx-js/mdx';
+import { createProcessor, nodeTypes } from '@mdx-js/mdx';
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
-import type { Literal, MemberExpression } from 'estree';
-import { visit as estreeVisit } from 'estree-util-visit';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
import remarkSmartypants from 'remark-smartypants';
-import type { VFile } from 'vfile';
+import { SourceMapGenerator } from 'source-map';
+import type { Processor } from 'unified';
import type { MdxOptions } from './index.js';
+import { recmaInjectImportMetaEnv } from './recma-inject-import-meta-env.js';
+import { rehypeApplyFrontmatterExport } from './rehype-apply-frontmatter-export.js';
import { rehypeInjectHeadingsExport } from './rehype-collect-headings.js';
import rehypeMetaString from './rehype-meta-string.js';
import { rehypeOptimizeStatic } from './rehype-optimize-static.js';
import { remarkImageToComponent } from './remark-images-to-component.js';
-import { jsToTreeNode } from './utils.js';
// Skip nonessential plugins during performance benchmark runs
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
-export function recmaInjectImportMetaEnvPlugin({
- importMetaEnv,
-}: {
+interface MdxProcessorExtraOptions {
+ sourcemap: boolean;
importMetaEnv: Record<string, any>;
-}) {
- return (tree: any) => {
- estreeVisit(tree, (node) => {
- if (node.type === 'MemberExpression') {
- // attempt to get "import.meta.env" variable name
- const envVarName = getImportMetaEnvVariableName(node);
- if (typeof envVarName === 'string') {
- // clear object keys to replace with envVarLiteral
- for (const key in node) {
- delete (node as any)[key];
- }
- const envVarLiteral: Literal = {
- type: 'Literal',
- value: importMetaEnv[envVarName],
- raw: JSON.stringify(importMetaEnv[envVarName]),
- };
- Object.assign(node, envVarLiteral);
- }
- }
- });
- };
}
-export function rehypeApplyFrontmatterExport() {
- return function (tree: any, vfile: VFile) {
- const astroData = safelyGetAstroData(vfile.data);
- if (astroData instanceof InvalidAstroDataError)
- throw new Error(
- // Copied from Astro core `errors-data`
- // TODO: find way to import error data from core
- '[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`.'
- );
- const { frontmatter } = astroData;
- const exportNodes = [
- jsToTreeNode(`export const frontmatter = ${JSON.stringify(frontmatter)};`),
- ];
- if (frontmatter.layout) {
- // NOTE(bholmesdev) 08-22-2022
- // Using an async layout import (i.e. `const Layout = (await import...)`)
- // Preserves the dev server import cache when globbing a large set of MDX files
- // Full explanation: 'https://github.com/withastro/astro/pull/4428'
- exportNodes.unshift(
- jsToTreeNode(
- /** @see 'vite-plugin-markdown' for layout props reference */
- `import { jsx as layoutJsx } from 'astro/jsx-runtime';
-
- export default async function ({ children }) {
- const Layout = (await import(${JSON.stringify(frontmatter.layout)})).default;
- const { layout, ...content } = frontmatter;
- content.file = file;
- content.url = url;
- return layoutJsx(Layout, {
- file,
- url,
- content,
- frontmatter: content,
- headings: getHeadings(),
- 'server:root': true,
- children,
- });
- };`
- )
- );
- }
- tree.children = exportNodes.concat(tree.children);
- };
+export function createMdxProcessor(
+ mdxOptions: MdxOptions,
+ extraOptions: MdxProcessorExtraOptions
+): Processor {
+ return createProcessor({
+ remarkPlugins: getRemarkPlugins(mdxOptions),
+ rehypePlugins: getRehypePlugins(mdxOptions),
+ recmaPlugins: getRecmaPlugins(mdxOptions, extraOptions.importMetaEnv),
+ remarkRehypeOptions: mdxOptions.remarkRehype,
+ jsx: true,
+ jsxImportSource: 'astro',
+ // Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
+ format: 'mdx',
+ mdExtensions: [],
+ elementAttributeNameCase: 'html',
+ SourceMapGenerator: extraOptions.sourcemap ? SourceMapGenerator : undefined,
+ });
}
-export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise<PluggableList> {
+function getRemarkPlugins(mdxOptions: MdxOptions): PluggableList {
let remarkPlugins: PluggableList = [remarkCollectImages, remarkImageToComponent];
if (!isPerformanceBenchmark) {
@@ -125,7 +73,7 @@ export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise<Pluggabl
return remarkPlugins;
}
-export function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
+function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
let rehypePlugins: PluggableList = [
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
rehypeMetaString,
@@ -152,38 +100,9 @@ export function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
return rehypePlugins;
}
-/**
- * Check if estree entry is "import.meta.env.VARIABLE"
- * If it is, return the variable name (i.e. "VARIABLE")
- */
-function getImportMetaEnvVariableName(node: MemberExpression): string | Error {
- try {
- // check for ".[ANYTHING]"
- if (node.object.type !== 'MemberExpression' || node.property.type !== 'Identifier')
- return new Error();
-
- const nestedExpression = node.object;
- // check for ".env"
- if (nestedExpression.property.type !== 'Identifier' || nestedExpression.property.name !== 'env')
- return new Error();
-
- const envExpression = nestedExpression.object;
- // check for ".meta"
- if (
- envExpression.type !== 'MetaProperty' ||
- envExpression.property.type !== 'Identifier' ||
- envExpression.property.name !== 'meta'
- )
- return new Error();
-
- // check for "import"
- if (envExpression.meta.name !== 'import') return new Error();
-
- return node.property.name;
- } catch (e) {
- if (e instanceof Error) {
- return e;
- }
- return new Error('Unknown parsing error');
- }
+function getRecmaPlugins(
+ mdxOptions: MdxOptions,
+ importMetaEnv: Record<string, any>
+): PluggableList {
+ return [...(mdxOptions.recmaPlugins ?? []), [recmaInjectImportMetaEnv, { importMetaEnv }]];
}