This commit is contained in:
Nicolas Dorseuil
2025-06-16 11:48:57 +02:00
parent a2fc076acb
commit aabdd3f4d7
4 changed files with 66 additions and 31 deletions
+24 -17
View File
@@ -47,7 +47,7 @@ const cachedInitialDate = cache(() => Date.now());
/**
* Fetches the page data matching the requested pathname and fallback to root page when page is not found.
*/
async function getPageDataWithFallback(args: {
export async function getPageDataWithFallback(args: {
context: GitBookSiteContext;
pagePathParams: PagePathParams;
}) {
@@ -63,28 +63,35 @@ async function getPageDataWithFallback(args: {
};
}
export async function getIcons(context: GitBookSiteContext): Promise<
{
url: string;
type: string;
media: string;
}[]
> {
return Promise.all([getIcon(context, 'light'), getIcon(context, 'dark')]).then((urls) => [
{
url: urls[0],
type: 'image/png',
media: '(prefers-color-scheme: light)',
},
{
url: urls[1],
type: 'image/png',
media: '(prefers-color-scheme: dark)',
},
]);
}
export const getPrefetchedDataFromLayoutParams = cache(
(params: RouteLayoutParams): PrefetchedLayoutData => {
const startingDate = cachedInitialDate();
const staticSiteContext = getStaticSiteContext(params).finally(() => {
console.log(`Finished fetching static site context in ${Date.now() - startingDate}ms`);
});
const icons = Promise.all([
staticSiteContext.then(({ context }) => getIcon(context, 'light')),
staticSiteContext.then(({ context }) => getIcon(context, 'dark')),
])
.then((urls) => [
{
url: urls[0],
type: 'image/png',
media: '(prefers-color-scheme: light)',
},
{
url: urls[1],
type: 'image/png',
media: '(prefers-color-scheme: dark)',
},
])
const icons = staticSiteContext
.then(({ context }) => getIcons(context))
.finally(() => {
console.log(`Finished fetching icons in ${Date.now() - startingDate}ms`);
});
@@ -11,6 +11,7 @@ import { getVisitorAuthClaims } from '@/lib/adaptive';
import { getSiteContentPointer } from '@/lib/pointer';
import { shouldTrackEvents } from '@/lib/tracking';
import { fetchV1ContextForSitePointer } from '@/lib/v1';
import { getIcons } from '@v2/lib/data/prefetch';
export const runtime = 'edge';
export const dynamic = 'force-dynamic';
@@ -44,7 +45,14 @@ export async function generateViewport(): Promise<Viewport> {
export async function generateMetadata(): Promise<Metadata> {
const context = await fetchLayoutData();
return generateSiteLayoutMetadata(context);
const icons = getIcons(context);
return generateSiteLayoutMetadata({
staticSiteContext: Promise.resolve({
context,
visitorAuthClaims: {},
}),
icons,
});
}
async function fetchLayoutData() {
@@ -27,7 +27,7 @@ export function PageBody(props: {
page: RevisionPageDocument;
ancestors: AncestorRevisionPage[];
document: JSONDocument | null;
prefetchedRef: Promise<Map<ContentRef, Promise<ResolvedContentRef | null>>>;
prefetchedRef?: Promise<Map<ContentRef, Promise<ResolvedContentRef | null>>>;
withPageFeedback: boolean;
}) {
const { page, context, ancestors, document, withPageFeedback } = props;
@@ -46,7 +46,7 @@ export function PageBody(props: {
if (!ref) {
return null;
}
if (options) {
if (options || !props.prefetchedRef) {
return resolveContentRef(ref, context, options);
}
return props.prefetchedRef.then((prefetched) => prefetched.get(ref) ?? null);
@@ -10,27 +10,41 @@ import { getPagePath } from '@/lib/pages';
import { isPageIndexable, isSiteIndexable } from '@/lib/seo';
import type { RouteParams } from '@v2/app/utils';
import { getPrefetchedDataFromPageParams } from '@v2/lib/data/prefetch';
import { getPageDocument } from '@v2/lib/data/pages';
import { getPageDataWithFallback, getPrefetchedDataFromPageParams } from '@v2/lib/data/prefetch';
import { getResizedImageURL } from '@v2/lib/images';
import { PageContextProvider } from '../PageContext';
import { PageClientLayout } from './PageClientLayout';
import { getPathnameParam } from './fetch';
import { type PagePathParams, getPathnameParam } from './fetch';
export type SitePageProps = {
context: GitBookSiteContext;
pageParams: RouteParams;
/**
* `RouteParams` is used in V2, `PagePathParams` is used in V1.
*/
pageParams: RouteParams | PagePathParams;
};
function isV2(params: RouteParams | PagePathParams): params is RouteParams {
return 'pagePath' in params;
}
/**
* Fetch and render a page.
*/
export async function SitePage(props: SitePageProps) {
console.log('Rendering site page', props.pageParams);
const prefetchedData = getPrefetchedDataFromPageParams(props.pageParams);
const { context, pageTarget } = await prefetchedData.pageData;
const prefetchedData = isV2(props.pageParams)
? getPrefetchedDataFromPageParams(props.pageParams)
: null;
const { context, pageTarget } = prefetchedData
? await prefetchedData.pageData
: await getPageDataWithFallback({
context: props.context,
pagePathParams: props.pageParams as PagePathParams,
});
const rawPathname = getPathnameParam({
pathname: props.pageParams.pagePath,
pathname: isV2(props.pageParams) ? props.pageParams.pagePath : props.pageParams.pathname,
});
if (!pageTarget) {
const pathname = rawPathname.toLowerCase();
@@ -65,7 +79,9 @@ export async function SitePage(props: SitePageProps) {
const withSections = Boolean(sections && sections.list.length > 0);
const headerOffset = { sectionsHeader: withSections, topHeader: withTopHeader };
const document = await prefetchedData.document;
const document = prefetchedData
? await prefetchedData.document
: await getPageDocument(context, page);
return (
<PageContextProvider pageId={page.id} spaceId={context.space.id} title={page.title}>
@@ -88,7 +104,7 @@ export async function SitePage(props: SitePageProps) {
ancestors={ancestors}
document={document}
withPageFeedback={withPageFeedback}
prefetchedRef={prefetchedData.prefetchedRef}
prefetchedRef={prefetchedData ? prefetchedData.prefetchedRef : undefined}
/>
</div>
<React.Suspense fallback={null}>
@@ -111,8 +127,12 @@ export async function generateSitePageViewport(context: GitBookSiteContext): Pro
}
export async function generateSitePageMetadata(props: SitePageProps): Promise<Metadata> {
const { context, pageTarget } = await getPrefetchedDataFromPageParams(props.pageParams)
.pageData;
const { context, pageTarget } = isV2(props.pageParams)
? await getPrefetchedDataFromPageParams(props.pageParams).pageData
: await getPageDataWithFallback({
context: props.context,
pagePathParams: props.pageParams as PagePathParams,
});
if (!pageTarget) {
notFound();