diff --git a/.changeset/silver-bananas-move.md b/.changeset/silver-bananas-move.md new file mode 100644 index 0000000000..583f647a6f --- /dev/null +++ b/.changeset/silver-bananas-move.md @@ -0,0 +1,13 @@ +--- +"astro": patch +--- + +Fixes an internal error that prevented the `AstroContainer` to render the `Content` component. + +You can now write code similar to the following to render content collections: + +```js +const entry = await getEntry(collection, slug); +const { Content } = await entry.render(); +const content = await container.renderToString(Content); +``` diff --git a/packages/astro/src/runtime/server/render/astro/render.ts b/packages/astro/src/runtime/server/render/astro/render.ts index c2d9533393..69d928d41d 100644 --- a/packages/astro/src/runtime/server/render/astro/render.ts +++ b/packages/astro/src/runtime/server/render/astro/render.ts @@ -148,6 +148,25 @@ async function callComponentAsTemplateResultOrResponse( if (factoryResult instanceof Response) { return factoryResult; + } + // we check if the component we attempt to render is a head+content + else if (isHeadAndContent(factoryResult)) { + // we make sure that content is valid template result + if (!isRenderTemplateResult(factoryResult.content)) { + throw new AstroError({ + ...AstroErrorData.OnlyResponseCanBeReturned, + message: AstroErrorData.OnlyResponseCanBeReturned.message( + route?.route, + typeof factoryResult + ), + location: { + file: route?.component, + }, + }); + } + + // return the content + return factoryResult.content; } else if (!isRenderTemplateResult(factoryResult)) { throw new AstroError({ ...AstroErrorData.OnlyResponseCanBeReturned, @@ -158,7 +177,7 @@ async function callComponentAsTemplateResultOrResponse( }); } - return isHeadAndContent(factoryResult) ? factoryResult.content : factoryResult; + return factoryResult; } // Recursively calls component instances that might have head content diff --git a/packages/astro/test/container.test.js b/packages/astro/test/container.test.js index c8b29a22a0..d9d3b8ae49 100644 --- a/packages/astro/test/container.test.js +++ b/packages/astro/test/container.test.js @@ -9,6 +9,8 @@ import { renderComponent, renderHead, renderSlot, + createHeadAndContent, + renderTemplate } from '../dist/runtime/server/index.js'; const BaseLayout = createComponent((result, _props, slots) => { @@ -140,6 +142,54 @@ describe('Container', () => { assert.match(result, /Bar name/); }); + it('Renders content and head component', async () => { + const Page = createComponent( + (result, _props, slots) => { + + return createHeadAndContent( + '', + renderTemplate`${renderComponent( + result, + 'BaseLayout', + BaseLayout, + {}, + { + default: () => render` + ${maybeRenderHead(result)} + ${renderSlot(result, slots['custom-name'])} + ${renderSlot(result, slots['foo-name'])} + `, + head: () => render` + ${renderComponent( + result, + 'Fragment', + Fragment, + { slot: 'head' }, + { + default: () => render``, + } + )} + `, + } + )}` + ); + }, + 'Component2.astro', + undefined + ); + + const container = await experimental_AstroContainer.create(); + const result = await container.renderToString(Page, { + slots: { + 'custom-name': 'Custom name', + 'foo-name': 'Bar name', + }, + }); + + assert.match(result, /Custom name/); + assert.match(result, /Bar name/); + }); + it('Renders props', async () => { const Page = createComponent( (result, props, _slots) => {