diff --git a/.changeset/purple-glasses-pretend.md b/.changeset/purple-glasses-pretend.md new file mode 100644 index 000000000000..bfba17393b76 --- /dev/null +++ b/.changeset/purple-glasses-pretend.md @@ -0,0 +1,14 @@ +--- +'astro': minor +--- + +Return raw `html` when calling `render()` on a markdown content. + +```astro +--- +const entry = await getEntryBySlug('blog', 'my-first-post'); +const { html } = await entry.render(); +--- + +
+``` diff --git a/packages/astro/src/content/internal.ts b/packages/astro/src/content/internal.ts index 04280166feb3..be21885b0816 100644 --- a/packages/astro/src/content/internal.ts +++ b/packages/astro/src/content/internal.ts @@ -175,9 +175,16 @@ async function render({ propagation: 'self', }); - return { + // This should match the RenderResult type from template/types.d.ts + const renderResult: Record = { Content, headings: mod.getHeadings(), remarkPluginFrontmatter: mod.frontmatter, }; + + if (!id.endsWith('mdx')) { + renderResult.html = mod.compiledContent(); + } + + return renderResult; } diff --git a/packages/astro/src/content/template/types.d.ts b/packages/astro/src/content/template/types.d.ts index f14a541f1e8a..7eaa5c6300fa 100644 --- a/packages/astro/src/content/template/types.d.ts +++ b/packages/astro/src/content/template/types.d.ts @@ -1,7 +1,7 @@ declare module 'astro:content' { export { z } from 'astro/zod'; export type CollectionEntry = - (typeof entryMap)[C][keyof (typeof entryMap)[C]] & Render; + (typeof entryMap)[C][keyof (typeof entryMap)[C]]; type BaseSchemaWithoutEffects = | import('astro/zod').AnyZodObject @@ -57,13 +57,17 @@ declare module 'astro:content' { Required['schema'] >; - type Render = { - render(): Promise<{ - Content: import('astro').MarkdownInstance<{}>['Content']; - headings: import('astro').MarkdownHeading[]; - remarkPluginFrontmatter: Record; - }>; - }; + interface RenderResult { + Content: import('astro').MarkdownInstance<{}>['Content']; + headings: import('astro').MarkdownHeading[]; + remarkPluginFrontmatter: Record; + html: undefined; + } + interface RenderResultWithHtml extends RenderResult { + html: string; + } + type Render = () => Promise; + type RenderWithHtml = () => Promise; const entryMap: { // @@ENTRY_MAP@@ diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts index b6f359b2cd85..de0d6bce2d9f 100644 --- a/packages/astro/src/content/types-generator.ts +++ b/packages/astro/src/content/types-generator.ts @@ -326,7 +326,8 @@ async function writeContentFiles({ const entryMetadata = contentTypes[collectionKey][entryKey]; const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any'; const slugType = JSON.stringify(entryMetadata.slug); - contentTypesStr += `${entryKey}: {\n id: ${entryKey},\n slug: ${slugType},\n body: string,\n collection: ${collectionKey},\n data: ${dataType}\n},\n`; + const renderType = JSON.parse(entryKey).endsWith('.mdx') ? 'Render' : 'RenderWithHtml'; + contentTypesStr += `${entryKey}: {\n id: ${entryKey},\n slug: ${slugType},\n body: string,\n collection: ${collectionKey},\n data: ${dataType},\n render: ${renderType}\n},\n`; } contentTypesStr += `},\n`; } diff --git a/packages/astro/test/content-collections-render.test.js b/packages/astro/test/content-collections-render.test.js index da14a4765f05..b47c191b7720 100644 --- a/packages/astro/test/content-collections-render.test.js +++ b/packages/astro/test/content-collections-render.test.js @@ -80,6 +80,13 @@ describe('Content Collections - render()', () => { expect(h2).to.have.a.lengthOf(1); expect(h2.attr('data-components-export-applied')).to.equal('true'); }); + + it('Renders with raw html for markdown content', async () => { + const html = await fixture.readFile('/render-with-html/index.html'); + const $ = cheerio.load(html); + + expect($('p').text()).to.equal('This is a post'); + }); }); describe('Build - SSR', () => { @@ -131,6 +138,16 @@ describe('Content Collections - render()', () => { expect(h2).to.have.a.lengthOf(1); expect(h2.attr('data-components-export-applied')).to.equal('true'); }); + + it('Renders with raw html for markdown content', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/render-with-html'); + const response = await app.render(request); + const html = await response.text(); + const $ = cheerio.load(html); + + expect($('p').text()).to.equal('This is a post'); + }); }); describe('Dev - SSG', () => { @@ -195,5 +212,15 @@ describe('Content Collections - render()', () => { expect(h2).to.have.a.lengthOf(1); expect(h2.attr('data-components-export-applied')).to.equal('true'); }); + + it('Renders with raw html for markdown content', async () => { + const response = await fixture.fetch('/render-with-html', { method: 'GET' }); + expect(response.status).to.equal(200); + + const html = await response.text(); + const $ = cheerio.load(html); + + expect($('p').text()).to.equal('This is a post'); + }); }); }); diff --git a/packages/astro/test/content-collections.test.js b/packages/astro/test/content-collections.test.js index c8105184e83b..96779c9cbde8 100644 --- a/packages/astro/test/content-collections.test.js +++ b/packages/astro/test/content-collections.test.js @@ -129,6 +129,22 @@ describe('Content Collections', () => { }); }); }); + + describe('Render HTML', () => { + let json; + before(async () => { + const rawJson = await fixture.readFile('/render-html.json'); + json = JSON.parse(rawJson); + }); + + it('Renders HTML correctly', async () => { + expect(json).to.deep.equal({ + one: '

one

', + three: '

three

', + two: '

two

', + }); + }); + }); }); const blogSlugToContents = { diff --git a/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/one.md b/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/one.md new file mode 100644 index 000000000000..b8aad57f977a --- /dev/null +++ b/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/one.md @@ -0,0 +1 @@ +# one diff --git a/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/three.md b/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/three.md new file mode 100644 index 000000000000..f49407daa8a3 --- /dev/null +++ b/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/three.md @@ -0,0 +1 @@ +# three diff --git a/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/two.md b/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/two.md new file mode 100644 index 000000000000..02f0d6c20b83 --- /dev/null +++ b/packages/astro/test/fixtures/content-collections/src/content/rss-markdown/two.md @@ -0,0 +1 @@ +# two diff --git a/packages/astro/test/fixtures/content-collections/src/pages/render-html.json.ts b/packages/astro/test/fixtures/content-collections/src/pages/render-html.json.ts new file mode 100644 index 000000000000..39280ff2761c --- /dev/null +++ b/packages/astro/test/fixtures/content-collections/src/pages/render-html.json.ts @@ -0,0 +1,12 @@ +import { getCollection } from 'astro:content'; + +export async function get() { + const collection = await getCollection('rss-markdown') + const result = {} + await Promise.all(collection.map(async (item) => { + result[item.slug] = (await item.render()).html + })) + return { + body: JSON.stringify(result) + } +} diff --git a/packages/astro/test/fixtures/content/src/pages/render-with-html.astro b/packages/astro/test/fixtures/content/src/pages/render-with-html.astro new file mode 100644 index 000000000000..887040f08774 --- /dev/null +++ b/packages/astro/test/fixtures/content/src/pages/render-with-html.astro @@ -0,0 +1,14 @@ +--- +import { getEntryBySlug } from 'astro:content'; + +const entry = await getEntryBySlug('blog', 'one'); +const { html } = await entry.render(); +--- + + + Launch Week + + +
+ +