mirror of
https://github.com/withastro/astro.git
synced 2024-12-16 21:46:22 -05:00
Move MDX Vite plugin to new file (#10854)
This commit is contained in:
parent
204b7820e6
commit
a3e95dbeb0
2 changed files with 93 additions and 88 deletions
|
@ -1,16 +1,14 @@
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { markdownConfigDefaults, setVfileFrontmatter } from '@astrojs/markdown-remark';
|
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
|
||||||
import type { AstroIntegration, ContentEntryType, HookParameters, SSRError } from 'astro';
|
import type { AstroIntegration, ContentEntryType, HookParameters } from 'astro';
|
||||||
import astroJSXRenderer from 'astro/jsx/renderer.js';
|
import astroJSXRenderer from 'astro/jsx/renderer.js';
|
||||||
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
||||||
import type { PluggableList } from 'unified';
|
import type { PluggableList } from 'unified';
|
||||||
import { VFile } from 'vfile';
|
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
|
||||||
import { createMdxProcessor } from './plugins.js';
|
|
||||||
import type { OptimizeOptions } from './rehype-optimize-static.js';
|
import type { OptimizeOptions } from './rehype-optimize-static.js';
|
||||||
import { getFileInfo, ignoreStringPlugins, parseFrontmatter } from './utils.js';
|
import { ignoreStringPlugins, parseFrontmatter } from './utils.js';
|
||||||
import { vitePluginMdxPostprocess } from './vite-plugin-mdx-postprocess.js';
|
import { vitePluginMdxPostprocess } from './vite-plugin-mdx-postprocess.js';
|
||||||
|
import { vitePluginMdx } from './vite-plugin-mdx.js';
|
||||||
|
|
||||||
export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
|
export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
|
||||||
extendMarkdownConfig: boolean;
|
extendMarkdownConfig: boolean;
|
||||||
|
@ -70,90 +68,9 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
let processor: ReturnType<typeof createMdxProcessor> | undefined;
|
|
||||||
|
|
||||||
updateConfig({
|
updateConfig({
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [
|
plugins: [vitePluginMdx(config, mdxOptions), vitePluginMdxPostprocess(config)],
|
||||||
{
|
|
||||||
name: '@mdx-js/rollup',
|
|
||||||
enforce: 'pre',
|
|
||||||
buildEnd() {
|
|
||||||
processor = undefined;
|
|
||||||
},
|
|
||||||
configResolved(resolved) {
|
|
||||||
processor = createMdxProcessor(mdxOptions, {
|
|
||||||
sourcemap: !!resolved.build.sourcemap,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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');
|
|
||||||
if (jsxPluginIndex !== -1) {
|
|
||||||
const myPluginIndex = resolved.plugins.findIndex(
|
|
||||||
(p) => p.name === '@mdx-js/rollup'
|
|
||||||
);
|
|
||||||
if (myPluginIndex !== -1) {
|
|
||||||
const myPlugin = resolved.plugins[myPluginIndex];
|
|
||||||
// @ts-ignore-error ignore readonly annotation
|
|
||||||
resolved.plugins.splice(myPluginIndex, 1);
|
|
||||||
// @ts-ignore-error ignore readonly annotation
|
|
||||||
resolved.plugins.splice(jsxPluginIndex, 0, myPlugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async resolveId(source, importer, options) {
|
|
||||||
if (importer?.endsWith('.mdx') && source[0] !== '/') {
|
|
||||||
let resolved = await this.resolve(source, importer, options);
|
|
||||||
if (!resolved) resolved = await this.resolve('./' + source, importer, options);
|
|
||||||
return resolved;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Override transform to alter code before MDX compilation
|
|
||||||
// ex. inject layouts
|
|
||||||
async transform(_, id) {
|
|
||||||
if (!id.endsWith('.mdx')) return;
|
|
||||||
|
|
||||||
// Read code from file manually to prevent Vite from parsing `import.meta.env` expressions
|
|
||||||
const { fileId } = getFileInfo(id, config);
|
|
||||||
const code = await fs.readFile(fileId, 'utf-8');
|
|
||||||
|
|
||||||
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
|
||||||
|
|
||||||
const vfile = new VFile({ value: pageContent, path: id });
|
|
||||||
// Ensure `data.astro` is available to all remark plugins
|
|
||||||
setVfileFrontmatter(vfile, frontmatter);
|
|
||||||
|
|
||||||
// `processor` is initialized in `configResolved`, and removed in `buildEnd`. `transform`
|
|
||||||
// should be called in between those two lifecycle, so this error should never happen
|
|
||||||
if (!processor) {
|
|
||||||
return this.error(
|
|
||||||
'MDX processor is not initialized. This is an internal error. Please file an issue.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const compiled = await processor.process(vfile);
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: String(compiled.value),
|
|
||||||
map: compiled.map,
|
|
||||||
};
|
|
||||||
} catch (e: any) {
|
|
||||||
const err: SSRError = e;
|
|
||||||
|
|
||||||
// For some reason MDX puts the error location in the error's name, not very useful for us.
|
|
||||||
err.name = 'MDXError';
|
|
||||||
err.loc = { file: fileId, line: e.line, column: e.column };
|
|
||||||
|
|
||||||
// For another some reason, MDX doesn't include a stack trace. Weird
|
|
||||||
Error.captureStackTrace(err);
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
vitePluginMdxPostprocess(config),
|
|
||||||
] as VitePlugin[],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
88
packages/integrations/mdx/src/vite-plugin-mdx.ts
Normal file
88
packages/integrations/mdx/src/vite-plugin-mdx.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
|
import { setVfileFrontmatter } from '@astrojs/markdown-remark';
|
||||||
|
import type { AstroConfig, SSRError } from 'astro';
|
||||||
|
import { VFile } from 'vfile';
|
||||||
|
import type { Plugin } from 'vite';
|
||||||
|
import { createMdxProcessor } from './plugins.js';
|
||||||
|
import { getFileInfo, parseFrontmatter } from './utils.js';
|
||||||
|
import type { MdxOptions } from './index.js';
|
||||||
|
|
||||||
|
export function vitePluginMdx(astroConfig: AstroConfig, mdxOptions: MdxOptions): Plugin {
|
||||||
|
let processor: ReturnType<typeof createMdxProcessor> | undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: '@mdx-js/rollup',
|
||||||
|
enforce: 'pre',
|
||||||
|
buildEnd() {
|
||||||
|
processor = undefined;
|
||||||
|
},
|
||||||
|
configResolved(resolved) {
|
||||||
|
processor = createMdxProcessor(mdxOptions, {
|
||||||
|
sourcemap: !!resolved.build.sourcemap,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
if (jsxPluginIndex !== -1) {
|
||||||
|
const myPluginIndex = resolved.plugins.findIndex((p) => p.name === '@mdx-js/rollup');
|
||||||
|
if (myPluginIndex !== -1) {
|
||||||
|
const myPlugin = resolved.plugins[myPluginIndex];
|
||||||
|
// @ts-ignore-error ignore readonly annotation
|
||||||
|
resolved.plugins.splice(myPluginIndex, 1);
|
||||||
|
// @ts-ignore-error ignore readonly annotation
|
||||||
|
resolved.plugins.splice(jsxPluginIndex, 0, myPlugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async resolveId(source, importer, options) {
|
||||||
|
if (importer?.endsWith('.mdx') && source[0] !== '/') {
|
||||||
|
let resolved = await this.resolve(source, importer, options);
|
||||||
|
if (!resolved) resolved = await this.resolve('./' + source, importer, options);
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Override transform to alter code before MDX compilation
|
||||||
|
// ex. inject layouts
|
||||||
|
async transform(_, id) {
|
||||||
|
if (!id.endsWith('.mdx')) return;
|
||||||
|
|
||||||
|
// Read code from file manually to prevent Vite from parsing `import.meta.env` expressions
|
||||||
|
const { fileId } = getFileInfo(id, astroConfig);
|
||||||
|
const code = await fs.readFile(fileId, 'utf-8');
|
||||||
|
|
||||||
|
const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
|
||||||
|
|
||||||
|
const vfile = new VFile({ value: pageContent, path: id });
|
||||||
|
// Ensure `data.astro` is available to all remark plugins
|
||||||
|
setVfileFrontmatter(vfile, frontmatter);
|
||||||
|
|
||||||
|
// `processor` is initialized in `configResolved`, and removed in `buildEnd`. `transform`
|
||||||
|
// should be called in between those two lifecycle, so this error should never happen
|
||||||
|
if (!processor) {
|
||||||
|
return this.error(
|
||||||
|
'MDX processor is not initialized. This is an internal error. Please file an issue.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const compiled = await processor.process(vfile);
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: String(compiled.value),
|
||||||
|
map: compiled.map,
|
||||||
|
};
|
||||||
|
} catch (e: any) {
|
||||||
|
const err: SSRError = e;
|
||||||
|
|
||||||
|
// For some reason MDX puts the error location in the error's name, not very useful for us.
|
||||||
|
err.name = 'MDXError';
|
||||||
|
err.loc = { file: fileId, line: e.line, column: e.column };
|
||||||
|
|
||||||
|
// For another some reason, MDX doesn't include a stack trace. Weird
|
||||||
|
Error.captureStackTrace(err);
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue