mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-16 23:55:20 +00:00
move to prefetch
This commit is contained in:
+1
-1
@@ -4,7 +4,7 @@ import {
|
||||
generateSitePageViewport,
|
||||
} from '@/components/SitePage';
|
||||
import type { RouteParams } from '@v2/app/utils';
|
||||
import { getPrefetchedDataFromLayoutParams } from '@v2/lib/data/memoize';
|
||||
import { getPrefetchedDataFromLayoutParams } from '@v2/lib/data/prefetch';
|
||||
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
generateSiteLayoutViewport,
|
||||
} from '@/components/SiteLayout';
|
||||
import { type RouteLayoutParams, getStaticSiteContext } from '@v2/app/utils';
|
||||
import { cachedDate, getPrefetchedDataFromLayoutParams } from '@v2/lib/data/memoize';
|
||||
import { getPrefetchedDataFromLayoutParams } from '@v2/lib/data/prefetch';
|
||||
import { GITBOOK_DISABLE_TRACKING } from '@v2/lib/env';
|
||||
|
||||
interface SiteStaticLayoutProps {
|
||||
@@ -16,8 +16,6 @@ export default async function SiteStaticLayout({
|
||||
params,
|
||||
children,
|
||||
}: React.PropsWithChildren<SiteStaticLayoutProps>) {
|
||||
const startedAt = cachedDate();
|
||||
console.info(`SiteStaticLayout: Starting to render static site layout at ${startedAt}`);
|
||||
const { context, visitorAuthClaims } = await getStaticSiteContext(await params);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
import { type PagePathParams, fetchPageData } from '@/components/SitePage/fetch';
|
||||
import type { VisitorAuthClaims } from '@/lib/adaptive';
|
||||
import type { AncestorRevisionPage } from '@/lib/pages';
|
||||
import { type ResolvedContentRef, resolveContentRef } from '@/lib/references';
|
||||
import type { ContentRef, JSONDocument, RevisionPageDocument } from '@gitbook/api';
|
||||
import {
|
||||
type RouteLayoutParams,
|
||||
type RouteParams,
|
||||
getIcon,
|
||||
getPagePathFromParams,
|
||||
getStaticSiteContext,
|
||||
} from '@v2/app/utils';
|
||||
import { cache } from 'react';
|
||||
import type { GitBookSiteContext } from '../context';
|
||||
import { getPageDocument } from './pages';
|
||||
|
||||
// This is used to create a context specific to the current request.
|
||||
// This version works both in cloudflare and in vercel.
|
||||
@@ -104,137 +90,3 @@ function deepSortValue(value: unknown): unknown {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export interface PrefetchedLayoutData {
|
||||
staticSiteContext: Promise<{
|
||||
context: GitBookSiteContext;
|
||||
visitorAuthClaims: VisitorAuthClaims;
|
||||
}>;
|
||||
icons: Promise<
|
||||
{
|
||||
url: string;
|
||||
type: string;
|
||||
media: string;
|
||||
}[]
|
||||
>;
|
||||
}
|
||||
|
||||
export interface PrefetchedPageData {
|
||||
pageData: Promise<{
|
||||
context: GitBookSiteContext & {
|
||||
page?: RevisionPageDocument;
|
||||
};
|
||||
pageTarget?: {
|
||||
page: RevisionPageDocument;
|
||||
ancestors: AncestorRevisionPage[];
|
||||
};
|
||||
}>;
|
||||
document: Promise<JSONDocument | null>;
|
||||
prefetchedRef: Promise<Map<ContentRef, Promise<ResolvedContentRef | null>>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the page data matching the requested pathname and fallback to root page when page is not found.
|
||||
*/
|
||||
async function getPageDataWithFallback(args: {
|
||||
context: GitBookSiteContext;
|
||||
pagePathParams: PagePathParams;
|
||||
}) {
|
||||
const { context: baseContext, pagePathParams } = args;
|
||||
const { context, pageTarget } = await fetchPageData(baseContext, pagePathParams);
|
||||
|
||||
return {
|
||||
context: {
|
||||
...context,
|
||||
page: pageTarget?.page,
|
||||
},
|
||||
pageTarget,
|
||||
};
|
||||
}
|
||||
|
||||
export const getPrefetchedDataFromLayoutParams = cache(
|
||||
(params: RouteLayoutParams): PrefetchedLayoutData => {
|
||||
const staticSiteContext = getStaticSiteContext(params);
|
||||
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)',
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
staticSiteContext,
|
||||
icons,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export const prefetchedDocumentRef = (
|
||||
document: JSONDocument | null,
|
||||
context: GitBookSiteContext
|
||||
) => {
|
||||
const fetched = new Map<ContentRef, Promise<ResolvedContentRef | null>>();
|
||||
if (!document) return fetched;
|
||||
|
||||
const traverseNodes = (nodes: any[]): void => {
|
||||
for (const node of nodes) {
|
||||
// We try prefetching as many references as possible.
|
||||
if (node.data?.ref) {
|
||||
fetched.set(node.data.ref, resolveContentRef(node.data.ref, context));
|
||||
}
|
||||
if (node.nodes && Array.isArray(node.nodes)) {
|
||||
traverseNodes(node.nodes);
|
||||
}
|
||||
if (node.fragments && Array.isArray(node.fragments)) {
|
||||
traverseNodes(node.fragments);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (document.nodes && Array.isArray(document.nodes)) {
|
||||
traverseNodes(document.nodes);
|
||||
}
|
||||
console.log('Prefetched document references:', fetched.size);
|
||||
return fetched;
|
||||
};
|
||||
|
||||
export const getPrefetchedDataFromPageParams = cache((params: RouteParams): PrefetchedPageData => {
|
||||
const { staticSiteContext } = getPrefetchedDataFromLayoutParams(params);
|
||||
const pathname = getPagePathFromParams(params);
|
||||
const pageData = staticSiteContext.then(({ context }) =>
|
||||
getPageDataWithFallback({
|
||||
context,
|
||||
pagePathParams: {
|
||||
pathname,
|
||||
},
|
||||
})
|
||||
);
|
||||
const document = pageData.then(({ context, pageTarget }) => {
|
||||
if (!pageTarget?.page) {
|
||||
return null;
|
||||
}
|
||||
return getPageDocument(context.dataFetcher, context.space, pageTarget?.page);
|
||||
});
|
||||
const prefetchedRef = Promise.all([staticSiteContext, document]).then(
|
||||
([{ context }, document]) => {
|
||||
// Prefetch the references in the document
|
||||
return prefetchedDocumentRef(document, context);
|
||||
}
|
||||
);
|
||||
return {
|
||||
pageData,
|
||||
document,
|
||||
prefetchedRef,
|
||||
};
|
||||
});
|
||||
|
||||
export const cachedDate = cache(() => Date.now());
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import { type PagePathParams, fetchPageData } from '@/components/SitePage';
|
||||
import type { VisitorAuthClaims } from '@/lib/adaptive';
|
||||
import type { AncestorRevisionPage } from '@/lib/pages';
|
||||
import { type ResolvedContentRef, resolveContentRef } from '@/lib/references';
|
||||
import type { ContentRef, JSONDocument, RevisionPageDocument } from '@gitbook/api';
|
||||
import {
|
||||
type RouteLayoutParams,
|
||||
type RouteParams,
|
||||
getIcon,
|
||||
getPagePathFromParams,
|
||||
getStaticSiteContext,
|
||||
} from '@v2/app/utils';
|
||||
import { cache } from 'react';
|
||||
import type { GitBookSiteContext } from '../context';
|
||||
import { getPageDocument } from './pages';
|
||||
|
||||
export interface PrefetchedLayoutData {
|
||||
staticSiteContext: Promise<{
|
||||
context: GitBookSiteContext;
|
||||
visitorAuthClaims: VisitorAuthClaims;
|
||||
}>;
|
||||
icons: Promise<
|
||||
{
|
||||
url: string;
|
||||
type: string;
|
||||
media: string;
|
||||
}[]
|
||||
>;
|
||||
}
|
||||
|
||||
export interface PrefetchedPageData {
|
||||
pageData: Promise<{
|
||||
context: GitBookSiteContext & {
|
||||
page?: RevisionPageDocument;
|
||||
};
|
||||
pageTarget?: {
|
||||
page: RevisionPageDocument;
|
||||
ancestors: AncestorRevisionPage[];
|
||||
};
|
||||
}>;
|
||||
document: Promise<JSONDocument | null>;
|
||||
prefetchedRef: Promise<Map<ContentRef, Promise<ResolvedContentRef | null>>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the page data matching the requested pathname and fallback to root page when page is not found.
|
||||
*/
|
||||
async function getPageDataWithFallback(args: {
|
||||
context: GitBookSiteContext;
|
||||
pagePathParams: PagePathParams;
|
||||
}) {
|
||||
const { context: baseContext, pagePathParams } = args;
|
||||
const { context, pageTarget } = await fetchPageData(baseContext, pagePathParams);
|
||||
|
||||
return {
|
||||
context: {
|
||||
...context,
|
||||
page: pageTarget?.page,
|
||||
},
|
||||
pageTarget,
|
||||
};
|
||||
}
|
||||
|
||||
export const getPrefetchedDataFromLayoutParams = cache(
|
||||
(params: RouteLayoutParams): PrefetchedLayoutData => {
|
||||
const staticSiteContext = getStaticSiteContext(params);
|
||||
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)',
|
||||
},
|
||||
]);
|
||||
|
||||
return {
|
||||
staticSiteContext,
|
||||
icons,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
export const prefetchedDocumentRef = (
|
||||
document: JSONDocument | null,
|
||||
context: GitBookSiteContext
|
||||
) => {
|
||||
const fetched = new Map<ContentRef, Promise<ResolvedContentRef | null>>();
|
||||
if (!document) return fetched;
|
||||
|
||||
const traverseNodes = (nodes: any[]): void => {
|
||||
for (const node of nodes) {
|
||||
// We try prefetching as many references as possible.
|
||||
if (node.data?.ref) {
|
||||
fetched.set(node.data.ref, resolveContentRef(node.data.ref, context));
|
||||
}
|
||||
if (node.nodes && Array.isArray(node.nodes)) {
|
||||
traverseNodes(node.nodes);
|
||||
}
|
||||
if (node.fragments && Array.isArray(node.fragments)) {
|
||||
traverseNodes(node.fragments);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (document.nodes && Array.isArray(document.nodes)) {
|
||||
traverseNodes(document.nodes);
|
||||
}
|
||||
console.log('Prefetched document references:', fetched.size);
|
||||
return fetched;
|
||||
};
|
||||
|
||||
export const getPrefetchedDataFromPageParams = cache((params: RouteParams): PrefetchedPageData => {
|
||||
const { staticSiteContext } = getPrefetchedDataFromLayoutParams(params);
|
||||
const pathname = getPagePathFromParams(params);
|
||||
const pageData = staticSiteContext.then(({ context }) =>
|
||||
getPageDataWithFallback({
|
||||
context,
|
||||
pagePathParams: {
|
||||
pathname,
|
||||
},
|
||||
})
|
||||
);
|
||||
const document = pageData.then(({ context, pageTarget }) => {
|
||||
if (!pageTarget?.page) {
|
||||
return null;
|
||||
}
|
||||
return getPageDocument(context, pageTarget?.page);
|
||||
});
|
||||
const prefetchedRef = Promise.all([staticSiteContext, document]).then(
|
||||
([{ context }, document]) => {
|
||||
// Prefetch the references in the document
|
||||
return prefetchedDocumentRef(document, context);
|
||||
}
|
||||
);
|
||||
return {
|
||||
pageData,
|
||||
document,
|
||||
prefetchedRef,
|
||||
};
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import { buildVersion } from '@/lib/build';
|
||||
import { isSiteIndexable } from '@/lib/seo';
|
||||
|
||||
import type { VisitorAuthClaims } from '@/lib/adaptive';
|
||||
import type { PrefetchedLayoutData } from '@v2/lib/data/memoize';
|
||||
import type { PrefetchedLayoutData } from '@v2/lib/data/prefetch';
|
||||
import { GITBOOK_API_PUBLIC_URL, GITBOOK_ASSETS_URL, GITBOOK_ICONS_URL } from '@v2/lib/env';
|
||||
import { ClientContexts } from './ClientContexts';
|
||||
import { RocketLoaderDetector } from './RocketLoaderDetector';
|
||||
|
||||
@@ -10,7 +10,7 @@ import { getPagePath } from '@/lib/pages';
|
||||
import { isPageIndexable, isSiteIndexable } from '@/lib/seo';
|
||||
|
||||
import type { RouteParams } from '@v2/app/utils';
|
||||
import { getPrefetchedDataFromPageParams } from '@v2/lib/data/memoize';
|
||||
import { getPrefetchedDataFromPageParams } from '@v2/lib/data/prefetch';
|
||||
import { getResizedImageURL } from '@v2/lib/images';
|
||||
import { PageContextProvider } from '../PageContext';
|
||||
import { PageClientLayout } from './PageClientLayout';
|
||||
|
||||
Reference in New Issue
Block a user