summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/heavy-tomatoes-know.md5
-rw-r--r--packages/astro/src/content/internal.ts39
-rw-r--r--packages/astro/src/content/vite-plugin-content-assets.ts4
-rw-r--r--packages/astro/test/content-collections-render.test.js33
-rw-r--r--packages/astro/test/fixtures/content/src/components/H2.astro4
-rw-r--r--packages/astro/test/fixtures/content/src/content/blog/promo/launch-week-components-export.mdx18
-rw-r--r--packages/astro/test/fixtures/content/src/pages/launch-week-components-export.astro14
7 files changed, 107 insertions, 10 deletions
diff --git a/.changeset/heavy-tomatoes-know.md b/.changeset/heavy-tomatoes-know.md
new file mode 100644
index 000000000..ae8fd2dac
--- /dev/null
+++ b/.changeset/heavy-tomatoes-know.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Apply MDX `components` export when rendering as a content collection entry
diff --git a/packages/astro/src/content/internal.ts b/packages/astro/src/content/internal.ts
index 2b8f8ba6f..04280166f 100644
--- a/packages/astro/src/content/internal.ts
+++ b/packages/astro/src/content/internal.ts
@@ -1,3 +1,4 @@
+import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { prependForwardSlash } from '../core/path.js';
import {
@@ -120,21 +121,32 @@ async function render({
id: string;
collectionToRenderEntryMap: CollectionToEntryMap;
}) {
+ const UnexpectedRenderError = new AstroError({
+ ...AstroErrorData.UnknownContentCollectionError,
+ message: `Unexpected error while rendering ${String(collection)} → ${String(id)}.`,
+ });
+
const lazyImport = collectionToRenderEntryMap[collection]?.[id];
- if (!lazyImport) throw new Error(`${String(collection)} → ${String(id)} does not exist.`);
+ if (typeof lazyImport !== 'function') throw UnexpectedRenderError;
+
+ const baseMod = await lazyImport();
+ if (baseMod == null || typeof baseMod !== 'object') throw UnexpectedRenderError;
- const mod = await lazyImport();
+ const { collectedStyles, collectedLinks, collectedScripts, getMod } = baseMod;
+ if (typeof getMod !== 'function') throw UnexpectedRenderError;
+ const mod = await getMod();
+ if (mod == null || typeof mod !== 'object') throw UnexpectedRenderError;
const Content = createComponent({
- factory(result, props, slots) {
+ factory(result, baseProps, slots) {
let styles = '',
links = '',
scripts = '';
- if (Array.isArray(mod?.collectedStyles)) {
- styles = mod.collectedStyles.map((style: any) => renderStyleElement(style)).join('');
+ if (Array.isArray(collectedStyles)) {
+ styles = collectedStyles.map((style: any) => renderStyleElement(style)).join('');
}
- if (Array.isArray(mod?.collectedLinks)) {
- links = mod.collectedLinks
+ if (Array.isArray(collectedLinks)) {
+ links = collectedLinks
.map((link: any) => {
return renderUniqueStylesheet(result, {
href: prependForwardSlash(link),
@@ -142,8 +154,17 @@ async function render({
})
.join('');
}
- if (Array.isArray(mod?.collectedScripts)) {
- scripts = mod.collectedScripts.map((script: any) => renderScriptElement(script)).join('');
+ if (Array.isArray(collectedScripts)) {
+ scripts = collectedScripts.map((script: any) => renderScriptElement(script)).join('');
+ }
+
+ let props = baseProps;
+ // Auto-apply MDX components export
+ if (id.endsWith('mdx')) {
+ props = {
+ components: mod.components ?? {},
+ ...baseProps,
+ };
}
return createHeadAndContent(
diff --git a/packages/astro/src/content/vite-plugin-content-assets.ts b/packages/astro/src/content/vite-plugin-content-assets.ts
index 54b84380d..fd73caf47 100644
--- a/packages/astro/src/content/vite-plugin-content-assets.ts
+++ b/packages/astro/src/content/vite-plugin-content-assets.ts
@@ -36,7 +36,9 @@ export function astroContentAssetPropagationPlugin({ mode }: { mode: string }):
if (isPropagatedAsset(id)) {
const basePath = id.split('?')[0];
const code = `
- export { Content, getHeadings, frontmatter } from ${JSON.stringify(basePath)};
+ export async function getMod() {
+ return import(${JSON.stringify(basePath)});
+ }
export const collectedLinks = ${JSON.stringify(LINKS_PLACEHOLDER)};
export const collectedStyles = ${JSON.stringify(STYLES_PLACEHOLDER)};
export const collectedScripts = ${JSON.stringify(SCRIPTS_PLACEHOLDER)};
diff --git a/packages/astro/test/content-collections-render.test.js b/packages/astro/test/content-collections-render.test.js
index 92015393c..da14a4765 100644
--- a/packages/astro/test/content-collections-render.test.js
+++ b/packages/astro/test/content-collections-render.test.js
@@ -71,6 +71,15 @@ describe('Content Collections - render()', () => {
'`WithScripts.astro` hoisted script included unexpectedly.'
).to.be.undefined;
});
+
+ it('Applies MDX components export', async () => {
+ const html = await fixture.readFile('/launch-week-components-export/index.html');
+ const $ = cheerio.load(html);
+
+ const h2 = $('h2');
+ expect(h2).to.have.a.lengthOf(1);
+ expect(h2.attr('data-components-export-applied')).to.equal('true');
+ });
});
describe('Build - SSR', () => {
@@ -110,6 +119,18 @@ describe('Content Collections - render()', () => {
// Includes styles
expect($('link[rel=stylesheet]')).to.have.a.lengthOf(0);
});
+
+ it('Applies MDX components export', async () => {
+ const app = await fixture.loadTestAdapterApp();
+ const request = new Request('http://example.com/launch-week-components-export');
+ const response = await app.render(request);
+ const html = await response.text();
+ const $ = cheerio.load(html);
+
+ const h2 = $('h2');
+ expect(h2).to.have.a.lengthOf(1);
+ expect(h2.attr('data-components-export-applied')).to.equal('true');
+ });
});
describe('Dev - SSG', () => {
@@ -162,5 +183,17 @@ describe('Content Collections - render()', () => {
// Includes inline script
expect($('script[data-is-inline]')).to.have.a.lengthOf(1);
});
+
+ it('Applies MDX components export', async () => {
+ const response = await fixture.fetch('/launch-week-components-export', { method: 'GET' });
+ expect(response.status).to.equal(200);
+
+ const html = await response.text();
+ const $ = cheerio.load(html);
+
+ const h2 = $('h2');
+ expect(h2).to.have.a.lengthOf(1);
+ expect(h2.attr('data-components-export-applied')).to.equal('true');
+ });
});
});
diff --git a/packages/astro/test/fixtures/content/src/components/H2.astro b/packages/astro/test/fixtures/content/src/components/H2.astro
new file mode 100644
index 000000000..d1ad359c2
--- /dev/null
+++ b/packages/astro/test/fixtures/content/src/components/H2.astro
@@ -0,0 +1,4 @@
+---
+---
+
+<h2 data-components-export-applied="true"><slot /></h2>
diff --git a/packages/astro/test/fixtures/content/src/content/blog/promo/launch-week-components-export.mdx b/packages/astro/test/fixtures/content/src/content/blog/promo/launch-week-components-export.mdx
new file mode 100644
index 000000000..40012b8ef
--- /dev/null
+++ b/packages/astro/test/fixtures/content/src/content/blog/promo/launch-week-components-export.mdx
@@ -0,0 +1,18 @@
+---
+title: 'Launch week!'
+description: 'Join us for the exciting launch of SPACE BLOG'
+publishedDate: 'Sat May 21 2022 00:00:00 GMT-0400 (Eastern Daylight Time)'
+tags: ['announcement']
+---
+
+import H2 from '../../../components/H2.astro';
+
+export const components = { h2: H2 };
+
+Join us for the space blog launch!
+
+## Details
+
+- THIS THURSDAY
+- Houston, TX
+- Dress code: **interstellar casual** ✨
diff --git a/packages/astro/test/fixtures/content/src/pages/launch-week-components-export.astro b/packages/astro/test/fixtures/content/src/pages/launch-week-components-export.astro
new file mode 100644
index 000000000..463e65191
--- /dev/null
+++ b/packages/astro/test/fixtures/content/src/pages/launch-week-components-export.astro
@@ -0,0 +1,14 @@
+---
+import { getEntryBySlug } from 'astro:content';
+
+const entry = await getEntryBySlug('blog', 'promo/launch-week-components-export');
+const { Content } = await entry.render();
+---
+<html>
+<head>
+ <title>Launch Week</title>
+</head>
+<body>
+ <Content />
+</body>
+</html>