Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow remark/rehype plugins added after mdx to work #10877

Merged
merged 5 commits into from Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/slimy-cobras-end.md
@@ -0,0 +1,7 @@
---
"@astrojs/mdx": major
---

Allows integrations after the MDX integration to update `markdown.remarkPlugins` and `markdown.rehypePlugins`, and have the plugins work in MDX too.

If you rely on the ordering before to not add remark/rehype plugins for MDX, you need to configure `@astrojs/mdx` with `extendMarkdownConfig: false` and explicitly specify the `remarkPlugins` and `rehypePlugins` options instead.
12 changes: 0 additions & 12 deletions packages/astro/test/units/dev/collections-renderentry.test.js
Expand Up @@ -84,18 +84,6 @@ _describe('Content Collections - render()', () => {
it('can be used in a layout component', async () => {
const fs = createFsWithFallback(
{
// Loading the content config with `astro:content` oddly
// causes this test to fail. Spoof a different src/content entry
// to ensure `existsSync` checks pass.
// TODO: revisit after addressing this issue
// https://github.com/withastro/astro/issues/6121
'/src/content/blog/promo/launch-week.mdx': `---
title: Launch Week
description: Astro is launching this week!
---
# Launch Week
- [x] Launch Astro
- [ ] Celebrate`,
'/src/components/Layout.astro': `
---
import { getCollection } from 'astro:content';
Expand Down
29 changes: 21 additions & 8 deletions packages/integrations/mdx/src/index.ts
Expand Up @@ -29,6 +29,10 @@ type SetupHookParams = HookParameters<'astro:config:setup'> & {
};

export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroIntegration {
// @ts-expect-error Temporarily assign an empty object here, which will be re-assigned by the
// `astro:config:done` hook later. This is so that `vitePluginMdx` can get hold of a reference earlier.
let mdxOptions: MdxOptions = {};

return {
name: '@astrojs/mdx',
hooks: {
Expand Down Expand Up @@ -58,21 +62,30 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
handlePropagation: true,
});

updateConfig({
vite: {
plugins: [vitePluginMdx(mdxOptions), vitePluginMdxPostprocess(config)],
},
});
},
'astro:config:done': ({ config }) => {
// We resolve the final MDX options here so that other integrations have a chance to modify
// `config.markdown` before we access it
const extendMarkdownConfig =
partialMdxOptions.extendMarkdownConfig ?? defaultMdxOptions.extendMarkdownConfig;

const mdxOptions = applyDefaultOptions({
const resolvedMdxOptions = applyDefaultOptions({
options: partialMdxOptions,
defaults: markdownConfigToMdxOptions(
extendMarkdownConfig ? config.markdown : markdownConfigDefaults
),
});

updateConfig({
vite: {
plugins: [vitePluginMdx(mdxOptions), vitePluginMdxPostprocess(config)],
},
});
// Mutate `mdxOptions` so that `vitePluginMdx` can reference the actual options
Object.assign(mdxOptions, resolvedMdxOptions);
// @ts-expect-error After we assign, we don't need to reference `mdxOptions` in this context anymore.
// Re-assign it so that the garbage can be collected later.
mdxOptions = {};
},
},
};
Expand All @@ -81,7 +94,8 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
const defaultMdxOptions = {
extendMarkdownConfig: true,
recmaPlugins: [],
};
optimize: false,
} satisfies Partial<MdxOptions>;

function markdownConfigToMdxOptions(markdownConfig: typeof markdownConfigDefaults): MdxOptions {
return {
Expand All @@ -90,7 +104,6 @@ function markdownConfigToMdxOptions(markdownConfig: typeof markdownConfigDefault
remarkPlugins: ignoreStringPlugins(markdownConfig.remarkPlugins),
rehypePlugins: ignoreStringPlugins(markdownConfig.rehypePlugins),
remarkRehype: (markdownConfig.remarkRehype as any) ?? {},
optimize: false,
};
}

Expand Down
4 changes: 4 additions & 0 deletions packages/integrations/mdx/src/vite-plugin-mdx.ts
Expand Up @@ -16,6 +16,10 @@ export function vitePluginMdx(mdxOptions: MdxOptions): Plugin {
processor = undefined;
},
configResolved(resolved) {
// `mdxOptions` should be populated at this point, but `astro sync` doesn't call `astro:config:done` :(
// Workaround this for now by skipping here. `astro sync` shouldn't call the `transform()` hook here anyways.
Comment on lines +19 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. @bholmesdev mentioned an issue with astro sync and Astro DB the other day, which I wonder if it might be related — it also uses astro:config:done in a similar pattern to this to assign settled integration state for use by plugins.

tables.get = () => dbConfig.tables;
seedFiles.get = () => integrationSeedPaths;

Maybe something that will need fixing in sync itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think it would be nice if the hook was called in Astro sync too. I initially did that, but walked back a bit because I'm unsure if this breaks the db integration.

I noticed the db integration is running the same startup code in both astro sync and astro:config:done, and I'm unsure what happens in astro sync if it runs that code twice. It should be something we can look into fixing in the future though.

if (Object.keys(mdxOptions).length === 0) return;

processor = createMdxProcessor(mdxOptions, {
sourcemap: !!resolved.build.sourcemap,
});
Expand Down
24 changes: 24 additions & 0 deletions packages/integrations/mdx/test/mdx-plugins.test.js
Expand Up @@ -64,6 +64,30 @@ describe('MDX plugins', () => {
assert.notEqual(selectRehypeExample(document), null);
});

it('supports custom rehype plugins from integrations', async () => {
const fixture = await buildFixture({
integrations: [
mdx(),
{
name: 'test',
hooks: {
'astro:config:setup': ({ updateConfig }) => {
updateConfig({
markdown: {
rehypePlugins: [rehypeExamplePlugin],
}
});
}
}
}
],
});
const html = await fixture.readFile(FILE);
const { document } = parseHTML(html);

assert.notEqual(selectRehypeExample(document), null);
});

it('supports custom rehype plugins with namespaced attributes', async () => {
const fixture = await buildFixture({
integrations: [
Expand Down