Improve MDX rendering performance (#8533)
This commit is contained in:
parent
2e8726feec
commit
74dc3edb30
10 changed files with 175 additions and 156 deletions
5
.changeset/thin-starfishes-love.md
Normal file
5
.changeset/thin-starfishes-love.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/mdx': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Improve MDX rendering performance by sharing processor instance
|
|
@ -74,6 +74,7 @@
|
||||||
"remark-rehype": "^10.1.0",
|
"remark-rehype": "^10.1.0",
|
||||||
"remark-shiki-twoslash": "^3.1.3",
|
"remark-shiki-twoslash": "^3.1.3",
|
||||||
"remark-toc": "^8.0.1",
|
"remark-toc": "^8.0.1",
|
||||||
|
"unified": "^10.1.2",
|
||||||
"vite": "^4.4.9"
|
"vite": "^4.4.9"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
|
import { markdownConfigDefaults, setVfileFrontmatter } from '@astrojs/markdown-remark';
|
||||||
import { toRemarkInitializeAstroData } from '@astrojs/markdown-remark/dist/internal.js';
|
|
||||||
import { compile as mdxCompile, type CompileOptions } from '@mdx-js/mdx';
|
|
||||||
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
||||||
import type { AstroIntegration, ContentEntryType, HookParameters, SSRError } from 'astro';
|
import type { AstroIntegration, ContentEntryType, HookParameters, SSRError } from 'astro';
|
||||||
import astroJSXRenderer from 'astro/jsx/renderer.js';
|
import astroJSXRenderer from 'astro/jsx/renderer.js';
|
||||||
|
@ -8,10 +6,9 @@ import { parse as parseESM } from 'es-module-lexer';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
||||||
import { SourceMapGenerator } from 'source-map';
|
|
||||||
import { VFile } from 'vfile';
|
import { VFile } from 'vfile';
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
import { getRehypePlugins, getRemarkPlugins, recmaInjectImportMetaEnvPlugin } from './plugins.js';
|
import { createMdxProcessor } from './plugins.js';
|
||||||
import type { OptimizeOptions } from './rehype-optimize-static.js';
|
import type { OptimizeOptions } from './rehype-optimize-static.js';
|
||||||
import {
|
import {
|
||||||
ASTRO_IMAGE_ELEMENT,
|
ASTRO_IMAGE_ELEMENT,
|
||||||
|
@ -84,21 +81,7 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mdxPluginOpts: CompileOptions = {
|
let processor: ReturnType<typeof createMdxProcessor>;
|
||||||
remarkPlugins: await getRemarkPlugins(mdxOptions),
|
|
||||||
rehypePlugins: getRehypePlugins(mdxOptions),
|
|
||||||
recmaPlugins: mdxOptions.recmaPlugins,
|
|
||||||
remarkRehypeOptions: mdxOptions.remarkRehype,
|
|
||||||
jsx: true,
|
|
||||||
jsxImportSource: 'astro',
|
|
||||||
// Note: disable `.md` (and other alternative extensions for markdown files like `.markdown`) support
|
|
||||||
format: 'mdx',
|
|
||||||
mdExtensions: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
let importMetaEnv: Record<string, any> = {
|
|
||||||
SITE: config.site,
|
|
||||||
};
|
|
||||||
|
|
||||||
updateConfig({
|
updateConfig({
|
||||||
vite: {
|
vite: {
|
||||||
|
@ -107,7 +90,10 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
||||||
name: '@mdx-js/rollup',
|
name: '@mdx-js/rollup',
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
configResolved(resolved) {
|
configResolved(resolved) {
|
||||||
importMetaEnv = { ...importMetaEnv, ...resolved.env };
|
processor = createMdxProcessor(mdxOptions, {
|
||||||
|
sourcemap: !!resolved.build.sourcemap,
|
||||||
|
importMetaEnv: { SITE: config.site, ...resolved.env },
|
||||||
|
});
|
||||||
|
|
||||||
// HACK: move ourselves before Astro's JSX plugin to transform things in the right order
|
// HACK: move ourselves before Astro's JSX plugin to transform things in the right order
|
||||||
const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === 'astro:jsx');
|
const jsxPluginIndex = resolved.plugins.findIndex((p) => p.name === 'astro:jsx');
|
||||||
|
@ -134,23 +120,13 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
||||||
const code = await fs.readFile(fileId, 'utf-8');
|
const code = await fs.readFile(fileId, 'utf-8');
|
||||||
|
|
||||||
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
||||||
try {
|
|
||||||
const compiled = await mdxCompile(new VFile({ value: pageContent, path: id }), {
|
const vfile = new VFile({ value: pageContent, path: id });
|
||||||
...mdxPluginOpts,
|
|
||||||
elementAttributeNameCase: 'html',
|
|
||||||
remarkPlugins: [
|
|
||||||
// Ensure `data.astro` is available to all remark plugins
|
// Ensure `data.astro` is available to all remark plugins
|
||||||
toRemarkInitializeAstroData({ userFrontmatter: frontmatter }),
|
setVfileFrontmatter(vfile, frontmatter);
|
||||||
...(mdxPluginOpts.remarkPlugins ?? []),
|
|
||||||
],
|
try {
|
||||||
recmaPlugins: [
|
const compiled = await processor.process(vfile);
|
||||||
...(mdxPluginOpts.recmaPlugins ?? []),
|
|
||||||
() => recmaInjectImportMetaEnvPlugin({ importMetaEnv }),
|
|
||||||
],
|
|
||||||
SourceMapGenerator: config.vite.build?.sourcemap
|
|
||||||
? SourceMapGenerator
|
|
||||||
: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: escapeViteEnvReferences(String(compiled.value)),
|
code: escapeViteEnvReferences(String(compiled.value)),
|
||||||
|
|
|
@ -4,101 +4,49 @@ import {
|
||||||
remarkPrism,
|
remarkPrism,
|
||||||
remarkShiki,
|
remarkShiki,
|
||||||
} from '@astrojs/markdown-remark';
|
} from '@astrojs/markdown-remark';
|
||||||
import {
|
import { createProcessor, nodeTypes } from '@mdx-js/mdx';
|
||||||
InvalidAstroDataError,
|
|
||||||
safelyGetAstroData,
|
|
||||||
} from '@astrojs/markdown-remark/dist/internal.js';
|
|
||||||
import { nodeTypes } from '@mdx-js/mdx';
|
|
||||||
import type { PluggableList } from '@mdx-js/mdx/lib/core.js';
|
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 rehypeRaw from 'rehype-raw';
|
||||||
import remarkGfm from 'remark-gfm';
|
import remarkGfm from 'remark-gfm';
|
||||||
import remarkSmartypants from 'remark-smartypants';
|
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 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 { rehypeInjectHeadingsExport } from './rehype-collect-headings.js';
|
||||||
import rehypeMetaString from './rehype-meta-string.js';
|
import rehypeMetaString from './rehype-meta-string.js';
|
||||||
import { rehypeOptimizeStatic } from './rehype-optimize-static.js';
|
import { rehypeOptimizeStatic } from './rehype-optimize-static.js';
|
||||||
import { remarkImageToComponent } from './remark-images-to-component.js';
|
import { remarkImageToComponent } from './remark-images-to-component.js';
|
||||||
import { jsToTreeNode } from './utils.js';
|
|
||||||
|
|
||||||
// Skip nonessential plugins during performance benchmark runs
|
// Skip nonessential plugins during performance benchmark runs
|
||||||
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
|
const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
|
||||||
|
|
||||||
export function recmaInjectImportMetaEnvPlugin({
|
interface MdxProcessorExtraOptions {
|
||||||
importMetaEnv,
|
sourcemap: boolean;
|
||||||
}: {
|
|
||||||
importMetaEnv: Record<string, any>;
|
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 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 function rehypeApplyFrontmatterExport() {
|
function getRemarkPlugins(mdxOptions: MdxOptions): PluggableList {
|
||||||
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 async function getRemarkPlugins(mdxOptions: MdxOptions): Promise<PluggableList> {
|
|
||||||
let remarkPlugins: PluggableList = [remarkCollectImages, remarkImageToComponent];
|
let remarkPlugins: PluggableList = [remarkCollectImages, remarkImageToComponent];
|
||||||
|
|
||||||
if (!isPerformanceBenchmark) {
|
if (!isPerformanceBenchmark) {
|
||||||
|
@ -125,7 +73,7 @@ export async function getRemarkPlugins(mdxOptions: MdxOptions): Promise<Pluggabl
|
||||||
return remarkPlugins;
|
return remarkPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
|
function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
|
||||||
let rehypePlugins: PluggableList = [
|
let rehypePlugins: PluggableList = [
|
||||||
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
|
// ensure `data.meta` is preserved in `properties.metastring` for rehype syntax highlighters
|
||||||
rehypeMetaString,
|
rehypeMetaString,
|
||||||
|
@ -152,38 +100,9 @@ export function getRehypePlugins(mdxOptions: MdxOptions): PluggableList {
|
||||||
return rehypePlugins;
|
return rehypePlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function getRecmaPlugins(
|
||||||
* Check if estree entry is "import.meta.env.VARIABLE"
|
mdxOptions: MdxOptions,
|
||||||
* If it is, return the variable name (i.e. "VARIABLE")
|
importMetaEnv: Record<string, any>
|
||||||
*/
|
): PluggableList {
|
||||||
function getImportMetaEnvVariableName(node: MemberExpression): string | Error {
|
return [...(mdxOptions.recmaPlugins ?? []), [recmaInjectImportMetaEnv, { importMetaEnv }]];
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import type { Literal, MemberExpression } from 'estree';
|
||||||
|
import { visit as estreeVisit } from 'estree-util-visit';
|
||||||
|
|
||||||
|
export function recmaInjectImportMetaEnv({
|
||||||
|
importMetaEnv,
|
||||||
|
}: {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { InvalidAstroDataError } from '@astrojs/markdown-remark';
|
||||||
|
import { safelyGetAstroData } from '@astrojs/markdown-remark/dist/internal.js';
|
||||||
|
import type { VFile } from 'vfile';
|
||||||
|
import { jsToTreeNode } from './utils.js';
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
}
|
|
@ -27,12 +27,14 @@ export function safelyGetAstroData(vfileData: Data): MarkdownAstroData | Invalid
|
||||||
return astro;
|
return astro;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAstroData(vfileData: Data, astroData: MarkdownAstroData) {
|
export function setVfileFrontmatter(vfile: VFile, frontmatter: Record<string, any>) {
|
||||||
vfileData.astro = astroData;
|
vfile.data ??= {};
|
||||||
|
vfile.data.astro ??= {};
|
||||||
|
(vfile.data.astro as any).frontmatter = frontmatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use `setAstroData` instead
|
* @deprecated Use `setVfileFrontmatter` instead
|
||||||
*/
|
*/
|
||||||
export function toRemarkInitializeAstroData({
|
export function toRemarkInitializeAstroData({
|
||||||
userFrontmatter,
|
userFrontmatter,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import type {
|
||||||
import {
|
import {
|
||||||
InvalidAstroDataError,
|
InvalidAstroDataError,
|
||||||
safelyGetAstroData,
|
safelyGetAstroData,
|
||||||
setAstroData,
|
setVfileFrontmatter,
|
||||||
} from './frontmatter-injection.js';
|
} from './frontmatter-injection.js';
|
||||||
import { loadPlugins } from './load-plugins.js';
|
import { loadPlugins } from './load-plugins.js';
|
||||||
import { rehypeHeadingIds } from './rehype-collect-headings.js';
|
import { rehypeHeadingIds } from './rehype-collect-headings.js';
|
||||||
|
@ -27,7 +27,7 @@ import { unified } from 'unified';
|
||||||
import { VFile } from 'vfile';
|
import { VFile } from 'vfile';
|
||||||
import { rehypeImages } from './rehype-images.js';
|
import { rehypeImages } from './rehype-images.js';
|
||||||
|
|
||||||
export { InvalidAstroDataError } from './frontmatter-injection.js';
|
export { InvalidAstroDataError, setVfileFrontmatter } from './frontmatter-injection.js';
|
||||||
export { rehypeHeadingIds } from './rehype-collect-headings.js';
|
export { rehypeHeadingIds } from './rehype-collect-headings.js';
|
||||||
export { remarkCollectImages } from './remark-collect-images.js';
|
export { remarkCollectImages } from './remark-collect-images.js';
|
||||||
export { remarkPrism } from './remark-prism.js';
|
export { remarkPrism } from './remark-prism.js';
|
||||||
|
@ -125,7 +125,7 @@ export async function createMarkdownProcessor(
|
||||||
return {
|
return {
|
||||||
async render(content, renderOpts) {
|
async render(content, renderOpts) {
|
||||||
const vfile = new VFile({ value: content, path: renderOpts?.fileURL });
|
const vfile = new VFile({ value: content, path: renderOpts?.fileURL });
|
||||||
setAstroData(vfile.data, { frontmatter: renderOpts?.frontmatter ?? {} });
|
setVfileFrontmatter(vfile, renderOpts?.frontmatter ?? {});
|
||||||
|
|
||||||
const result: MarkdownVFile = await parser.process(vfile).catch((err) => {
|
const result: MarkdownVFile = await parser.process(vfile).catch((err) => {
|
||||||
// Ensure that the error message contains the input filename
|
// Ensure that the error message contains the input filename
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
export {
|
export {
|
||||||
InvalidAstroDataError,
|
InvalidAstroDataError,
|
||||||
safelyGetAstroData,
|
safelyGetAstroData,
|
||||||
setAstroData,
|
|
||||||
toRemarkInitializeAstroData,
|
toRemarkInitializeAstroData,
|
||||||
} from './frontmatter-injection.js';
|
} from './frontmatter-injection.js';
|
||||||
|
|
|
@ -4108,6 +4108,9 @@ importers:
|
||||||
remark-toc:
|
remark-toc:
|
||||||
specifier: ^8.0.1
|
specifier: ^8.0.1
|
||||||
version: 8.0.1
|
version: 8.0.1
|
||||||
|
unified:
|
||||||
|
specifier: ^10.1.2
|
||||||
|
version: 10.1.2
|
||||||
vite:
|
vite:
|
||||||
specifier: ^4.4.9
|
specifier: ^4.4.9
|
||||||
version: 4.4.9(@types/node@18.17.8)(sass@1.66.1)
|
version: 4.4.9(@types/node@18.17.8)(sass@1.66.1)
|
||||||
|
|
Loading…
Reference in a new issue