Skip to content

Improve API docs build performance and reduce build invalidation#601

Merged
IEvangelist merged 2 commits intomainfrom
dapine/optimize-build-times
Mar 25, 2026
Merged

Improve API docs build performance and reduce build invalidation#601
IEvangelist merged 2 commits intomainfrom
dapine/optimize-build-times

Conversation

@IEvangelist
Copy link
Member

Summary

This change addresses the API docs build regression by reducing repeated work during API page generation and trimming a couple of broad build inputs.

  • memoize API collection loads and sidebar generation in production builds
  • scope C# and TypeScript API sidebars to the current package/module instead of rendering the full API catalog on every page
  • apply a few sidebar micro-optimizations to avoid extra scans/sorts on scoped sidebars
  • make write-git-env.mjs deterministic and avoid rewriting .env.local when values do not change
  • replace the eager docs-wide glob in Include.astro with targeted docs collection lookup

Validation

  • did not run pnpm build locally
  • git diff --check
  • pnpm exec prettier --check on changed files
  • isolated smoke test for src/frontend/scripts/write-git-env.mjs

Notes

Route fan-out reduction was intentionally left out of this PR.

Copilot AI review requested due to automatic review settings March 23, 2026 23:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR targets an API docs build regression by reducing repeated work during Astro API page generation and trimming overly-broad build inputs, especially for sidebars and docs includes.

Changes:

  • Memoizes packages/tsModules collection loads and API sidebar generation in production builds.
  • Scopes C# and TypeScript API sidebars to the current package/module for most API pages (instead of building the full catalog per page).
  • Makes write-git-env.mjs deterministic and avoids rewriting .env.local when content hasn’t changed; replaces docs-wide eager globbing in Include.astro with a targeted docs collection lookup.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/frontend/src/utils/ts-modules.ts Memoizes TypeScript module collection loads in production and applies minor formatting cleanups.
src/frontend/src/utils/ts-api-sidebar.ts Adds production memoization and supports building a sidebar scoped to a specific TS package/module.
src/frontend/src/utils/packages.ts Memoizes package collection loads in production and applies minor formatting cleanups.
src/frontend/src/utils/api-sidebar.ts Adds production memoization and supports building a sidebar scoped to a specific C# package; includes small sidebar micro-optimizations.
src/frontend/src/pages/reference/api/typescript/[module]/index.astro Uses a package-scoped TS sidebar instead of the full-catalog sidebar.
src/frontend/src/pages/reference/api/typescript/[module]/[item]/index.astro Uses a package-scoped TS sidebar instead of the full-catalog sidebar.
src/frontend/src/pages/reference/api/typescript/[module]/[item]/[member]/index.astro Uses a package-scoped TS sidebar instead of the full-catalog sidebar.
src/frontend/src/pages/reference/api/csharp/[package]/index.astro Uses a package-scoped C# sidebar instead of the full-catalog sidebar.
src/frontend/src/pages/reference/api/csharp/[package]/[type]/index.astro Uses a package-scoped C# sidebar instead of the full-catalog sidebar.
src/frontend/src/pages/reference/api/csharp/[package]/[type]/[memberKind].astro Uses a package-scoped C# sidebar instead of the full-catalog sidebar.
src/frontend/src/components/Include.astro Replaces eager docs-wide globbing with getEntry('docs', ...) + render(...) for targeted includes.
src/frontend/scripts/write-git-env.mjs Uses CI-provided commit SHA or git rev-parse HEAD, and avoids rewriting .env.local unless values change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@IEvangelist IEvangelist reopened this Mar 24, 2026
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@IEvangelist IEvangelist requested a review from eerhardt March 25, 2026 05:06
Comment on lines +14 to +15
// Resolve the include through the docs collection instead of eagerly globbing
// the entire docs tree into every page that uses <Include>.
Copy link
Member

Choose a reason for hiding this comment

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

What does this comment mean? Why is it saying "instead of eagerly globbing the entire docs tree"?

Copy link
Member Author

Choose a reason for hiding this comment

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

The code before, was doing this:

 ...(import.meta.glob('/src/content/docs/**/*.md', { eager: true }) as Record<string, unknown>),
  ...(import.meta.glob('/src/content/docs/**/*.mdx', { eager: true }) as Record<string, unknown>),

Which eagerly enumerated ALL matching .md and .mdx files. Which was not good for perf.

import { getCollection } from 'astro:content';

let packagesPromise: Promise<any[]> | undefined;
const shouldCachePackages = import.meta.env.PROD;
Copy link
Member

Choose a reason for hiding this comment

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

Why change the behavior on PROD?

Copy link
Member Author

Choose a reason for hiding this comment

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

Locally, during dev, if we have a cached version - it's less of a concern. On PROD, we want to ensure we build from the latest regardless.

import { getCollection } from 'astro:content';

let tsModulesPromise: Promise<any[]> | undefined;
const shouldCacheTsModules = import.meta.env.PROD;
Copy link
Member

Choose a reason for hiding this comment

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

Same question on PROD

Copy link
Member Author

Choose a reason for hiding this comment

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

Same as above.

Comment on lines 164 to +206
@@ -178,10 +203,7 @@ export function simplifyType(typeRef: string): string {

// Clean assembly metadata from generic type arguments:
// System.IEquatable`1[[TypeName, Assembly, Version=..., ...]] → System.IEquatable`1[[TypeName]]
stripped = stripped.replace(
/\[\[([^\],]+),\s*[^\]]*\]\]/g,
'[[$1]]',
);
stripped = stripped.replace(/\[\[([^\],]+),\s*[^\]]*\]\]/g, '[[$1]]');
Copy link
Member

Choose a reason for hiding this comment

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

(nit) was it random to decide when to put a single statement on a line vs. when to put it all on one line?

These 2 changes appear to be just formatting changes, but in the opposite directions.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a good callout. We do have a linter/formatting rule. We don't enforce though, as it's a bit heavy handed - while it might add a bit of extra review work, we don't want to block PRs.

@IEvangelist IEvangelist enabled auto-merge (squash) March 25, 2026 23:30
@IEvangelist IEvangelist merged commit 5acdd6f into main Mar 25, 2026
5 checks passed
@IEvangelist IEvangelist deleted the dapine/optimize-build-times branch March 25, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants