Skip to content

Commit

Permalink
optimization(runtime): create smaller objects for each Astro global (w…
Browse files Browse the repository at this point in the history
…ithastro#10773)

* optimization(runtime): create smaller objects for each Astro global

* add changeset

* Make slots lazy

---------

Co-authored-by: bluwy <bjornlu.dev@gmail.com>
  • Loading branch information
2 people authored and PeterDraex committed Apr 23, 2024
1 parent 9879f22 commit d515a74
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-rats-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro": patch
---

Improves performance for frequent use of small components.
59 changes: 49 additions & 10 deletions packages/astro/src/core/render-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,57 @@ export class RenderContext {
return result;
}

#astroPagePartial?: Omit<AstroGlobal, 'props' | 'self' | 'slots'>;
/**
* The Astro global is sourced in 3 different phases:
* - **Static**: `.generator` and `.glob` is printed by the compiler, instantiated once per process per astro file
* - **Page-level**: `.request`, `.cookies`, `.locals` etc. These remain the same for the duration of the request.
* - **Component-level**: `.props`, `.slots`, and `.self` are unique to each _use_ of each component.
*
* The page level partial is used as the prototype of the user-visible `Astro` global object, which is instantiated once per use of a component.
*/
createAstro(
result: SSRResult,
astroGlobalPartial: AstroGlobalPartial,
astroStaticPartial: AstroGlobalPartial,
props: Record<string, any>,
slotValues: Record<string, any> | null
): AstroGlobal {
// Create page partial with static partial so they can be cached together.
const astroPagePartial = (this.#astroPagePartial ??= this.createAstroPagePartial(
result,
astroStaticPartial
));
// Create component-level partials. `Astro.self` is added by the compiler.
const astroComponentPartial = { props, self: null };

// Create final object. `Astro.slots` will be lazily created.
const Astro: Omit<AstroGlobal, 'self' | 'slots'> = Object.assign(
Object.create(astroPagePartial),
astroComponentPartial
);

// Handle `Astro.slots`
let _slots: AstroGlobal['slots'];
Object.defineProperty(Astro, 'slots', {
get: () => {
if (!_slots) {
_slots = new Slots(
result,
slotValues,
this.pipeline.logger
) as unknown as AstroGlobal['slots'];
}
return _slots;
},
});

return Astro as AstroGlobal;
}

createAstroPagePartial(
result: SSRResult,
astroStaticPartial: AstroGlobalPartial
): Omit<AstroGlobal, 'props' | 'self' | 'slots'> {
const renderContext = this;
const { cookies, locals, params, pipeline, request, url } = this;
const { response } = result;
Expand All @@ -260,12 +305,10 @@ export class RenderContext {
}
return new Response(null, { status, headers: { Location: path } });
};
const slots = new Slots(result, slotValues, pipeline.logger) as unknown as AstroGlobal['slots'];

// `Astro.self` is added by the compiler
const astroGlobalCombined: Omit<AstroGlobal, 'self'> = {
generator: astroGlobalPartial.generator,
glob: astroGlobalPartial.glob,
return {
generator: astroStaticPartial.generator,
glob: astroStaticPartial.glob,
cookies,
get clientAddress() {
return renderContext.clientAddress();
Expand All @@ -280,17 +323,13 @@ export class RenderContext {
get preferredLocaleList() {
return renderContext.computePreferredLocaleList();
},
props,
locals,
redirect,
request,
response,
slots,
site: pipeline.site,
url,
};

return astroGlobalCombined as AstroGlobal;
}

clientAddress() {
Expand Down

0 comments on commit d515a74

Please sign in to comment.