Skip to content

Commit

Permalink
Added more clarification around using Astro.slots.render (#4456)
Browse files Browse the repository at this point in the history
* Add an error message for when something that's not an array is passed to Astro.slots.render

* Add changeset

* Add more details
  • Loading branch information
Princesseuh authored Aug 25, 2022
1 parent 78334b9 commit 47e71ae
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/unlucky-otters-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Added an error message when the second argument of Astro.slots.render is not an array
17 changes: 16 additions & 1 deletion packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export interface AstroGlobal extends AstroGlobalPartial {
*/
has(slotName: string): boolean;
/**
* Asychronously renders this slot and returns HTML
* Asynchronously renders this slot and returns a string
*
* Example usage:
* ```astro
Expand All @@ -216,6 +216,21 @@ export interface AstroGlobal extends AstroGlobalPartial {
* <Fragment set:html={html} />
* ```
*
* A second parameters can be used to pass arguments to a slotted callback
*
* Example usage:
* ```astro
* ---
* html = await Astro.slots.render('default', ["Hello", "World"])
* ---
* ```
* Each item in the array will be passed as an argument that you can use like so:
* ```astro
* <Component>
* {(hello, world) => <div>{hello}, {world}!</div>}
* </Component>
* ```
*
* [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroslots)
*/
render(slotName: string, args?: any[]): Promise<string>;
Expand Down
24 changes: 18 additions & 6 deletions packages/astro/src/core/render/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,13 @@ class Slots {
#cache = new Map<string, string>();
#result: SSRResult;
#slots: Record<string, any> | null;
#loggingOpts: LogOptions;

constructor(result: SSRResult, slots: Record<string, any> | null) {
constructor(result: SSRResult, slots: Record<string, any> | null, logging: LogOptions) {
this.#result = result;
this.#slots = slots;
this.#loggingOpts = logging;

if (slots) {
for (const key of Object.keys(slots)) {
if ((this as any)[key] !== undefined) {
Expand Down Expand Up @@ -92,11 +95,20 @@ class Slots {
if (!cacheable) {
const component = await this.#slots[name]();
const expression = getFunctionExpression(component);
if (expression) {
const slot = expression(...args);
return await renderSlot(this.#result, slot).then((res) =>
res != null ? String(res) : res

if (!Array.isArray(args)) {
warn(
this.#loggingOpts,
'Astro.slots.render',
`Expected second parameter to be an array, received a ${typeof args}. If you're trying to pass an array as a single argument and getting unexpected results, make sure you're passing your array as a item of an array. Ex: Astro.slots.render('default', [["Hello", "World"]])`
);
} else {
if (expression) {
const slot = expression(...args);
return await renderSlot(this.#result, slot).then((res) =>
res != null ? String(res) : res
);
}
}
}
const content = await renderSlot(this.#result, this.#slots[name]).then((res) =>
Expand Down Expand Up @@ -146,7 +158,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
props: Record<string, any>,
slots: Record<string, any> | null
) {
const astroSlots = new Slots(result, slots);
const astroSlots = new Slots(result, slots, args.logging);

const Astro = {
__proto__: astroGlobal,
Expand Down

0 comments on commit 47e71ae

Please sign in to comment.