mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-04 21:32:15 +00:00
perf: optimize docs static generation cost (#12108)
## Summary - Switch the docs catch-all route to full static generation and prebuild both latest and versioned docs paths. - Prebuild OG images for all docs pages, make sitemap and LLM export static, and remove nondeterministic sitemap timestamps. - Reduce build-time overhead by memoizing docs sidebar trees and skipping processed markdown generation for versioned docs. ## Testing - `pnpm nx run @zitadel/docs:build` - `pnpm nx run @zitadel/docs:lint` - `pnpm nx run @zitadel/docs:check-types` - Verified the prerender manifest contains 8,816 prerendered routes, 3,293 versioned docs routes, 4,406 OG routes, and zero revalidating docs routes.
This commit is contained in:
@@ -1,69 +1,61 @@
|
||||
import { source, versionSource } from '@/lib/source';
|
||||
import { getAllDocPages, source, versionSource } from '@/lib/source';
|
||||
import { ReactNode } from 'react';
|
||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||
import { baseOptions } from '@/lib/layout.shared';
|
||||
import { buildCustomTree } from '@/lib/custom-tree';
|
||||
import rawVersions from '@/content/versions.json';
|
||||
|
||||
const versions = rawVersions as any[];
|
||||
import { VersionSelector } from '@/components/version-selector';
|
||||
|
||||
type DocVersion = { param: string };
|
||||
type PageTree = typeof source.pageTree;
|
||||
|
||||
const versions = rawVersions as DocVersion[];
|
||||
const versionParams = new Set(versions.map((version) => version.param));
|
||||
|
||||
const labelsMap = new Map<string, string>();
|
||||
for (const page of getAllDocPages()) {
|
||||
if (page.data.sidebar_label) {
|
||||
labelsMap.set(page.url, page.data.sidebar_label);
|
||||
}
|
||||
}
|
||||
|
||||
const latestTree = buildCustomTree(source.pageTree, { labels: labelsMap });
|
||||
const versionTreeCache = new Map<string, PageTree>();
|
||||
|
||||
function getVersionTree(currentVersion: string): PageTree {
|
||||
const cached = versionTreeCache.get(currentVersion);
|
||||
if (cached) return cached;
|
||||
|
||||
const children = (versionSource.pageTree as any).children || [];
|
||||
const versionFolder = children.find((node: any) => {
|
||||
if (node.type !== 'folder') return false;
|
||||
if (node.index?.url && node.index.url.includes(`/${currentVersion}`)) return true;
|
||||
return Boolean(node.children?.[0]?.url?.includes(`/${currentVersion}`));
|
||||
});
|
||||
|
||||
const tree = versionFolder
|
||||
? buildCustomTree(
|
||||
{
|
||||
name: versionFolder.name,
|
||||
children: versionFolder.children,
|
||||
} as any,
|
||||
{
|
||||
stripPrefix: `/${currentVersion}`,
|
||||
labels: labelsMap,
|
||||
},
|
||||
)
|
||||
: buildCustomTree(versionSource.pageTree, { labels: labelsMap });
|
||||
|
||||
versionTreeCache.set(currentVersion, tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
export default async function Layout(props: { children: ReactNode; params: Promise<{ slug?: string[] }> }) {
|
||||
const params = await props.params;
|
||||
const slug = params.slug || [];
|
||||
|
||||
// Determine current version and tail path
|
||||
// If first slug segment matches a version param (e.g. v4.10), that's the version.
|
||||
// Otherwise it's latest.
|
||||
const versionParam = slug[0] && versions.find(v => v.param === slug[0]) ? slug[0] : undefined;
|
||||
const currentVersion = versionParam || 'latest';
|
||||
|
||||
const allPages = [...source.getPages(), ...versionSource.getPages()];
|
||||
const labelsMap = new Map<string, string>();
|
||||
allPages.forEach(p => {
|
||||
if (p.data.sidebar_label) {
|
||||
labelsMap.set(p.url, p.data.sidebar_label);
|
||||
}
|
||||
});
|
||||
|
||||
let tree: typeof source.pageTree;
|
||||
if (currentVersion !== 'latest') {
|
||||
// Hoist the version folder to root to flatten sidebar
|
||||
// versionSource.pageTree -> [ v4.10 folder, v4.9 folder ... ]
|
||||
// We want the children of the specific version folder.
|
||||
|
||||
const children = (versionSource.pageTree as any).children || [];
|
||||
|
||||
const versionFolder = children.find((node: any) => {
|
||||
if (node.type !== 'folder') return false;
|
||||
// Check if the folder's index page belongs to this version
|
||||
if (node.index?.url && node.index.url.includes(`/${currentVersion}`)) return true;
|
||||
// Fallback: check first child if index missing
|
||||
if (node.children?.[0]?.url?.includes(`/${currentVersion}`)) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
if (versionFolder) {
|
||||
// Hoist children
|
||||
const hoistedTree = {
|
||||
name: versionFolder.name,
|
||||
children: versionFolder.children,
|
||||
} as any;
|
||||
|
||||
// Apply custom sidebar structure (from local sidebar-data.ts)
|
||||
// We strip the prefix '/v4.10' so the lookup matches generic keys 'guides/...'
|
||||
// The logs showed the URLs start with /[version] not /docs/[version]
|
||||
const prefix = currentVersion === 'latest' ? '/docs' : `/${currentVersion}`;
|
||||
tree = buildCustomTree(hoistedTree, {
|
||||
stripPrefix: prefix,
|
||||
labels: labelsMap
|
||||
});
|
||||
} else {
|
||||
tree = buildCustomTree(versionSource.pageTree, { labels: labelsMap });
|
||||
}
|
||||
} else {
|
||||
tree = buildCustomTree(source.pageTree, { labels: labelsMap });
|
||||
}
|
||||
const currentVersion = slug[0] && versionParams.has(slug[0]) ? slug[0] : 'latest';
|
||||
const tree = currentVersion === 'latest' ? latestTree : getVersionTree(currentVersion);
|
||||
|
||||
return (
|
||||
<DocsLayout
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getPageImage, getPage, source } from '@/lib/source';
|
||||
import { generateAllDocParams, getPageImage, getPage, source } from '@/lib/source';
|
||||
import {
|
||||
DocsBody,
|
||||
DocsPage,
|
||||
@@ -43,7 +43,7 @@ export const revalidate = false;
|
||||
export const dynamic = 'force-static';
|
||||
|
||||
export async function generateStaticParams() {
|
||||
return source.generateParams();
|
||||
return generateAllDocParams();
|
||||
}
|
||||
|
||||
export async function generateMetadata(
|
||||
|
||||
Reference in New Issue
Block a user