Skip to content

perf: avoid structuredClone in sidebar generation for prerendered builds#3761

Closed
MohamedH1998 wants to merge 1 commit intowithastro:mainfrom
MohamedH1998:perf/avoid-structuredclone-sidebar-prerender
Closed

perf: avoid structuredClone in sidebar generation for prerendered builds#3761
MohamedH1998 wants to merge 1 commit intowithastro:mainfrom
MohamedH1998:perf/avoid-structuredclone-sidebar-prerender

Conversation

@MohamedH1998
Copy link
Copy Markdown

Description

During prerendered builds, generateRouteData was calling getSidebar on every page, which does a full structuredClone of the intermediate sidebar tree on each call. For large sites this is O(n) allocations × number of pages (in our case 7303 page).
This PR introduces a fast path getSidebarForRender — that mutates the shared intermediate sidebar in place by flipping a single isCurrent pointer per call, reducing sidebar work to O(1) per page during static builds.

As a POC, I've implemented a patch to the package in our repo which saw a significant decrease in build times, see here

Changes

utils/navigation.ts

  • Add getSidebarForRender: mutates the cached intermediate sidebar in place, tracking the previously-current link per locale so it can be reset on the next call without a full tree scan.
  • Add resetCurrentEntries: ensures the clone path (getSidebar / getSidebarFromConfig) always starts from a clean state, guarding against stale isCurrent flags if the intermediate cache was previously mutated by the fast path.
  • Add findAndMarkCurrentEntry: shared helper for the in-place mutation path.
    utils/routing/data.ts
  • Branch on config.prerender in generateRouteData: use getSidebarForRender for static builds, getSidebar for SSR.
  • structuredClone the result of getSidebarForRender before handing it off to the route data object, so each page's sidebar snapshot is isolated from subsequent mutations.
    relevant tests

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 16, 2026

Deploy Preview for astro-starlight ready!

Name Link
🔨 Latest commit 29f745a
🔍 Latest deploy log https://app.netlify.com/projects/astro-starlight/deploys/69b8423728dc0500088150d4
😎 Deploy Preview https://deploy-preview-3761--astro-starlight.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 100 (no change from production)
Accessibility: 100 (no change from production)
Best Practices: 100 (no change from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 16, 2026

🦋 Changeset detected

Latest commit: 29f745a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@astrojs/starlight Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added the 🌟 core Changes to Starlight’s main package label Mar 16, 2026
@astrobot-houston
Copy link
Copy Markdown
Contributor

Hello! Thank you for opening your first PR to Starlight! ✨

Here’s what will happen next:

  1. Our GitHub bots will run to check your changes.
    If they spot any issues you will see some error messages on this PR.
    Don’t hesitate to ask any questions if you’re not sure what these mean!

  2. In a few minutes, you’ll be able to see a preview of your changes on Netlify 🤩

  3. One or more of our maintainers will take a look and may ask you to make changes.
    We try to be responsive, but don’t worry if this takes a few days.

Copy link
Copy Markdown
Member

@delucis delucis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR @MohamedH1998!

I have a feeling this is maybe adding much more code than necessary unless I misunderstood something. Could you explain why you needed the additional findAndMarkCurrentEntry() function (which is basically identical to the existing setIntermediateSidebarCurrentEntry()) and the separate getSidebarRender() function?

IIUC the sidebar could use identical code in prerendered and on-demand builds, with the only difference being that when prerendering, it’s safe to skip the structured clone. Does that sound right to you? If so, the changes can probably be much more minimal.

delucis added a commit that referenced this pull request Mar 19, 2026
Inspired by #3761 but with an implementation that is closer to the existing architecture and avoids some unnecessary code duplication.
@delucis
Copy link
Copy Markdown
Member

delucis commented Mar 19, 2026

@MohamedH1998 I opened an alternative approach to removing structuredClone here which avoids some of the things I was concerned about in this PR.

Would you be able to test it on your Cloudflare Docs branch to see how it performs?

You can install a preview release with:

pnpm add https://pkg.pr.new/@astrojs/starlight@3768

@MohamedH1998
Copy link
Copy Markdown
Author

@delucis FYI, we've bumped our starlight version and saw the same improvements! Appreciate you getting it sorted so quickly

@delucis
Copy link
Copy Markdown
Member

delucis commented Mar 24, 2026

Awesome, thanks for letting us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🌟 core Changes to Starlight’s main package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants