diff options
author | 2025-03-18 10:32:07 +0100 | |
---|---|---|
committer | 2025-03-18 09:32:07 +0000 | |
commit | defad33140dccde324b9357bc6331f7e5cdec266 (patch) | |
tree | be4ac16548c94ef2364f30a78d8cad3a8bc29a5d | |
parent | 7783dbf8117650c60d7633b43f0d42da487aa2b1 (diff) | |
download | astro-defad33140dccde324b9357bc6331f7e5cdec266.tar.gz astro-defad33140dccde324b9357bc6331f7e5cdec266.tar.zst astro-defad33140dccde324b9357bc6331f7e5cdec266.zip |
fix: renderToString function not render properly nested slots when they are components (#13432)
* Fix/render to string slots (#1)
* add force HTMLString with local tests
* remove local test & logs
* remove test counter in basic exemple
* re-add test & create SlotString instead of HTMLString
* add test of a nested rendered component inside renderToString slots function
* add changeset on astro package
* Apply suggestions from code review
---------
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com>
-rw-r--r-- | .changeset/wide-carrots-dream.md | 5 | ||||
-rw-r--r-- | examples/container-with-vitest/src/components/CounterLight.astro | 9 | ||||
-rw-r--r-- | examples/container-with-vitest/test/Card.test.ts | 14 | ||||
-rw-r--r-- | packages/astro/src/container/index.ts | 13 |
4 files changed, 41 insertions, 0 deletions
diff --git a/.changeset/wide-carrots-dream.md b/.changeset/wide-carrots-dream.md new file mode 100644 index 000000000..b0e30081e --- /dev/null +++ b/.changeset/wide-carrots-dream.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix an issue in the Container API, where the `renderToString` function doesn't render adequately nested slots when they are components. diff --git a/examples/container-with-vitest/src/components/CounterLight.astro b/examples/container-with-vitest/src/components/CounterLight.astro new file mode 100644 index 000000000..7cee23bbe --- /dev/null +++ b/examples/container-with-vitest/src/components/CounterLight.astro @@ -0,0 +1,9 @@ +--- +interface Props { + count?: number; +} + +let { count = 0 } = Astro.props; +--- + +<p id="counter">{count}</p> diff --git a/examples/container-with-vitest/test/Card.test.ts b/examples/container-with-vitest/test/Card.test.ts index 26d766d1a..119087a36 100644 --- a/examples/container-with-vitest/test/Card.test.ts +++ b/examples/container-with-vitest/test/Card.test.ts @@ -1,6 +1,7 @@ import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import { expect, test } from 'vitest'; import Card from '../src/components/Card.astro'; +import CounterLight from '../src/components/CounterLight.astro'; test('Card with slots', async () => { const container = await AstroContainer.create(); @@ -13,3 +14,16 @@ test('Card with slots', async () => { expect(result).toContain('This is a card'); expect(result).toContain('Card content'); }); + +test('Card with nested CounterLight', async () => { + const container = await AstroContainer.create(); + const counterLight = await container.renderToString(CounterLight, { props: { count: 1 } }); + const result = await container.renderToString(Card, { + slots: { + default: counterLight, + }, + }); + + expect(result).toContain('This is a card'); + expect(result).toContain(counterLight); +}); diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 0a1b854d1..3943ad57b 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -26,6 +26,7 @@ import type { SSRResult, } from '../types/public/internal.js'; import { ContainerPipeline } from './pipeline.js'; +import { SlotString } from '../runtime/server/render/slot.js'; /** Public type, used for integrations to define a renderer for the container API */ export type ContainerRenderer = { @@ -474,6 +475,10 @@ export class experimental_AstroContainer { component: AstroComponentFactory, options: ContainerRenderOptions = {}, ): Promise<string> { + if (options.slots) { + options.slots = markAllSlotsAsSlotString(options.slots); + } + const response = await this.renderToResponse(component, options); return await response.text(); } @@ -588,3 +593,11 @@ export class experimental_AstroContainer { function isNamedRenderer(renderer: any): renderer is NamedSSRLoadedRendererValue { return !!renderer?.name; } + +function markAllSlotsAsSlotString(slots: Record<string, any>): Record<string, any> { + const markedSlots: Record<string, any> = {}; + for (const slotName in slots) { + markedSlots[slotName] = new SlotString(slots[slotName], null); + } + return markedSlots; +} |