Skip to content

Commit

Permalink
fix(slots): consume eagerly rendered slot after one use (#8929)
Browse files Browse the repository at this point in the history
* render slots lazily

* add test

* add changeset

* refactor

* reword changeset
  • Loading branch information
lilnasy authored Nov 1, 2023
1 parent 4a0fec9 commit 2da33b7
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/plenty-spiders-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes an issue where rendering the same slot multiple times invoked it only once.
14 changes: 12 additions & 2 deletions packages/astro/src/runtime/server/render/astro/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,18 @@ export class AstroComponentInstance {
this.factory = factory;
this.slotValues = {};
for (const name in slots) {
const value = slots[name](result);
this.slotValues[name] = () => value;
// prerender the slots eagerly to make collection entries propagate styles and scripts
let didRender = false;
let value = slots[name](result);
this.slotValues[name] = () => {
// use prerendered value only once
if (!didRender) {
didRender = true;
return value;
}
// render afresh for the advanced use-case where the same slot is rendered multiple times
return slots[name](result);
};
}
}

Expand Down
14 changes: 14 additions & 0 deletions packages/astro/test/astro-slots.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,19 @@ describe('Slots', () => {
expect($('#render-args span')).to.have.lengthOf(1);
expect($('#render-args').text()).to.equal('render-args');
}

{
const html = await fixture.readFile('/rendered-multiple-times/index.html');
const $ = cheerio.load(html);

const elements = $('div');
expect(elements).to.have.lengthOf(10);

const [ first, second, third ] = elements;

expect(first.children[0].data).to.not.equal(second.children[0].data);
expect(second.children[0].data).to.not.equal(third.children[0].data);
expect(third.children[0].data).to.not.equal(first.children[0].data);
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
const randomNumber = Math.random();
---
<div>
{randomNumber}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
interface Props {
count: number;
}
const {count} = Astro.props;
const renders: string[] = [];
for (let i = 0; i < count; i++) {
renders.push(await Astro.slots.render('default'));
}
---

{renders.map(
(render, i) => <Fragment key={i} set:html={render} />
)}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
import RandomCard from '../components/Random.astro';
import RenderMulti from '../components/RenderMultipleTimes.astro';
---
<RenderMulti count={10}>
<RandomCard/>
</RenderMulti>

0 comments on commit 2da33b7

Please sign in to comment.