Skip to content

Commit

Permalink
Merge branch 'main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterDraex authored Apr 23, 2024
2 parents a231779 + d7dff64 commit be1979b
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 88 deletions.
93 changes: 5 additions & 88 deletions packages/integrations/mdx/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import fs from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { markdownConfigDefaults, setVfileFrontmatter } from '@astrojs/markdown-remark';
import type { AstroIntegration, ContentEntryType, HookParameters, SSRError } from 'astro';
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
import type { AstroIntegration, ContentEntryType, HookParameters } from 'astro';
import astroJSXRenderer from 'astro/jsx/renderer.js';
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
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 { getFileInfo, ignoreStringPlugins, parseFrontmatter } from './utils.js';
import { ignoreStringPlugins, parseFrontmatter } from './utils.js';
import { vitePluginMdxPostprocess } from './vite-plugin-mdx-postprocess.js';
import { vitePluginMdx } from './vite-plugin-mdx.js';

export type MdxOptions = Omit<typeof markdownConfigDefaults, 'remarkPlugins' | 'rehypePlugins'> & {
extendMarkdownConfig: boolean;
Expand Down Expand Up @@ -70,90 +68,9 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
),
});

let processor: ReturnType<typeof createMdxProcessor> | undefined;

updateConfig({
vite: {
plugins: [
{
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[],
plugins: [vitePluginMdx(config, mdxOptions), vitePluginMdxPostprocess(config)],
},
});
},
Expand Down
88 changes: 88 additions & 0 deletions packages/integrations/mdx/src/vite-plugin-mdx.ts
Original file line number Diff line number Diff line change
@@ -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 type { MdxOptions } from './index.js';
import { createMdxProcessor } from './plugins.js';
import { getFileInfo, parseFrontmatter } from './utils.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;
}
},
};
}

0 comments on commit be1979b

Please sign in to comment.