mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-20 17:43:24 +00:00
Refactor content reference handling to use getContentRef method across components
This commit is contained in:
@@ -42,6 +42,8 @@ export interface PrefetchedPageData {
|
||||
prefetchedRef: Promise<Map<ContentRef, Promise<ResolvedContentRef | null>>>;
|
||||
}
|
||||
|
||||
const cachedInitialDate = cache(() => Date.now());
|
||||
|
||||
/**
|
||||
* Fetches the page data matching the requested pathname and fallback to root page when page is not found.
|
||||
*/
|
||||
@@ -63,22 +65,29 @@ async function getPageDataWithFallback(args: {
|
||||
|
||||
export const getPrefetchedDataFromLayoutParams = cache(
|
||||
(params: RouteLayoutParams): PrefetchedLayoutData => {
|
||||
const staticSiteContext = getStaticSiteContext(params);
|
||||
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)',
|
||||
},
|
||||
]);
|
||||
])
|
||||
.then((urls) => [
|
||||
{
|
||||
url: urls[0],
|
||||
type: 'image/png',
|
||||
media: '(prefers-color-scheme: light)',
|
||||
},
|
||||
{
|
||||
url: urls[1],
|
||||
type: 'image/png',
|
||||
media: '(prefers-color-scheme: dark)',
|
||||
},
|
||||
])
|
||||
.finally(() => {
|
||||
console.log(`Finished fetching icons in ${Date.now() - startingDate}ms`);
|
||||
});
|
||||
|
||||
return {
|
||||
staticSiteContext,
|
||||
@@ -112,33 +121,43 @@ export const prefetchedDocumentRef = (
|
||||
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 startingDate = cachedInitialDate();
|
||||
const { staticSiteContext } = getPrefetchedDataFromLayoutParams(params);
|
||||
const pathname = getPagePathFromParams(params);
|
||||
const pageData = staticSiteContext.then(({ context }) =>
|
||||
getPageDataWithFallback({
|
||||
context,
|
||||
pagePathParams: {
|
||||
pathname,
|
||||
},
|
||||
const pageData = staticSiteContext
|
||||
.then(({ context }) =>
|
||||
getPageDataWithFallback({
|
||||
context,
|
||||
pagePathParams: {
|
||||
pathname,
|
||||
},
|
||||
})
|
||||
)
|
||||
.finally(() => {
|
||||
console.log(`Finished fetching page data in ${Date.now() - startingDate}ms`);
|
||||
});
|
||||
const document = pageData
|
||||
.then(({ context, pageTarget }) => {
|
||||
if (!pageTarget?.page) {
|
||||
return null;
|
||||
}
|
||||
return getPageDocument(context, pageTarget?.page);
|
||||
})
|
||||
);
|
||||
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]) => {
|
||||
.finally(() => {
|
||||
console.log(`Finished fetching document in ${Date.now() - startingDate}ms`);
|
||||
});
|
||||
const prefetchedRef = Promise.all([staticSiteContext, document])
|
||||
.then(([{ context }, document]) => {
|
||||
// Prefetch the references in the document
|
||||
return prefetchedDocumentRef(document, context);
|
||||
}
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
console.log(`Finished prefetching references in ${Date.now() - startingDate}ms`);
|
||||
});
|
||||
return {
|
||||
pageData,
|
||||
document,
|
||||
|
||||
@@ -48,6 +48,7 @@ export function PlainCodeBlock(props: { code: string; syntax: string }) {
|
||||
document={document}
|
||||
context={{
|
||||
mode: 'default',
|
||||
getContentRef: async () => null, // No content references needed for plain code block
|
||||
}}
|
||||
block={block}
|
||||
ancestorBlocks={[]}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ClassValue } from '@/lib/tailwind';
|
||||
import type { ContentRef, JSONDocument } from '@gitbook/api';
|
||||
import type { GitBookAnyContext } from '@v2/lib/context';
|
||||
|
||||
import type { ResolvedContentRef } from '@/lib/references';
|
||||
import type { ResolveContentRefOptions, ResolvedContentRef } from '@/lib/references';
|
||||
import { BlockSkeleton } from './Block';
|
||||
import { Blocks } from './Blocks';
|
||||
|
||||
@@ -30,7 +30,10 @@ export interface DocumentContext {
|
||||
*/
|
||||
wrapBlocksInSuspense?: boolean;
|
||||
|
||||
contentRef?: Promise<Map<ContentRef, Promise<ResolvedContentRef | null>>>;
|
||||
getContentRef: (
|
||||
ref: ContentRef,
|
||||
options?: ResolveContentRefOptions
|
||||
) => Promise<ResolvedContentRef | null>;
|
||||
}
|
||||
|
||||
export interface DocumentContextProps {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { type DocumentInlineLink, SiteInsightsLinkPosition } from '@gitbook/api';
|
||||
|
||||
import { resolveContentRef } from '@/lib/references';
|
||||
import { Icon } from '@gitbook/icons';
|
||||
import { StyledLink } from '../primitives';
|
||||
import type { InlineProps } from './Inline';
|
||||
@@ -10,16 +8,7 @@ import { Inlines } from './Inlines';
|
||||
export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
||||
const { inline, document, context, ancestorInlines } = props;
|
||||
|
||||
const refs = await context.contentRef;
|
||||
|
||||
const resolved =
|
||||
(await refs?.get(inline.data.ref)) ??
|
||||
(context.contentContext
|
||||
? await resolveContentRef(inline.data.ref, context.contentContext, {
|
||||
// We don't want to resolve the anchor text here, as it can be very expensive and will block rendering if there is a lot of anchors link.
|
||||
resolveAnchorText: false,
|
||||
})
|
||||
: null);
|
||||
const resolved = await context.getContentRef(inline.data.ref);
|
||||
|
||||
if (!context.contentContext || !resolved) {
|
||||
return (
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
|
||||
import { LinkBox, LinkOverlay } from '@/components/primitives';
|
||||
import { Image } from '@/components/utils';
|
||||
import { resolveContentRef } from '@/lib/references';
|
||||
import { type ClassValue, tcls } from '@/lib/tailwind';
|
||||
|
||||
import { RecordColumnValue } from './RecordColumnValue';
|
||||
@@ -28,12 +27,8 @@ export async function RecordCard(
|
||||
: null;
|
||||
|
||||
const [cover, target] = await Promise.all([
|
||||
coverFile && context.contentContext
|
||||
? resolveContentRef({ kind: 'file', file: coverFile }, context.contentContext)
|
||||
: null,
|
||||
targetRef && context.contentContext
|
||||
? resolveContentRef(targetRef, context.contentContext)
|
||||
: null,
|
||||
coverFile ? context.getContentRef({ kind: 'file', file: coverFile }) : null,
|
||||
targetRef && context.getContentRef(targetRef),
|
||||
]);
|
||||
|
||||
const coverIsSquareOrPortrait =
|
||||
|
||||
@@ -28,6 +28,7 @@ import { PageControlButtons } from './PageControlButtons';
|
||||
import { PrintButton } from './PrintButton';
|
||||
import './pdf.css';
|
||||
import { sanitizeGitBookAppURL } from '@/lib/app';
|
||||
import { resolveContentRef } from '@/lib/references';
|
||||
import { getPageDocument } from '@v2/lib/data';
|
||||
|
||||
const DEFAULT_LIMIT = 100;
|
||||
@@ -244,6 +245,8 @@ async function PDFPageDocument(props: {
|
||||
...context,
|
||||
page,
|
||||
},
|
||||
//TODO: Use prefetchedRef to avoid fetching the same content multiple times
|
||||
getContentRef: (ref, options) => resolveContentRef(ref, context, options),
|
||||
getId: (id) => getPagePDFContainerId(page, id),
|
||||
}}
|
||||
// We consider all pages as offscreen in PDF mode
|
||||
|
||||
@@ -6,7 +6,11 @@ import { getSpaceLanguage } from '@/intl/server';
|
||||
import { t } from '@/intl/translate';
|
||||
import { hasFullWidthBlock, isNodeEmpty } from '@/lib/document';
|
||||
import type { AncestorRevisionPage } from '@/lib/pages';
|
||||
import type { ResolvedContentRef } from '@/lib/references';
|
||||
import {
|
||||
type ResolveContentRefOptions,
|
||||
type ResolvedContentRef,
|
||||
resolveContentRef,
|
||||
} from '@/lib/references';
|
||||
import { tcls } from '@/lib/tailwind';
|
||||
import { DocumentView, DocumentViewSkeleton } from '../DocumentView';
|
||||
import { TrackPageViewEvent } from '../Insights';
|
||||
@@ -35,6 +39,19 @@ export function PageBody(props: {
|
||||
const language = getSpaceLanguage(customization);
|
||||
const updatedAt = page.updatedAt ?? page.createdAt;
|
||||
|
||||
const getContentRef = async (
|
||||
ref?: ContentRef,
|
||||
options?: ResolveContentRefOptions
|
||||
): Promise<ResolvedContentRef | null> => {
|
||||
if (!ref) {
|
||||
return null;
|
||||
}
|
||||
if (!options) {
|
||||
return resolveContentRef(ref, context, options);
|
||||
}
|
||||
return props.prefetchedRef.then((prefetched) => prefetched.get(ref) ?? null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<main
|
||||
@@ -70,7 +87,7 @@ export function PageBody(props: {
|
||||
context={{
|
||||
mode: 'default',
|
||||
contentContext: context,
|
||||
contentRef: props.prefetchedRef,
|
||||
getContentRef: getContentRef,
|
||||
}}
|
||||
/>
|
||||
</React.Suspense>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { createStreamableValue } from 'ai/rsc';
|
||||
import type * as React from 'react';
|
||||
|
||||
import { joinPathWithBaseURL } from '@/lib/paths';
|
||||
import { resolveContentRef } from '@/lib/references';
|
||||
import { isV2 } from '@/lib/v2';
|
||||
import type { IconName } from '@gitbook/icons';
|
||||
import { throwIfDataError } from '@v2/lib/data';
|
||||
@@ -345,6 +346,9 @@ async function transformAnswer(
|
||||
mode: 'default',
|
||||
contentContext: undefined,
|
||||
wrapBlocksInSuspense: false,
|
||||
// TODO: Use prefetched content references
|
||||
getContentRef: async (ref, options) =>
|
||||
resolveContentRef(ref, context, options),
|
||||
}}
|
||||
style={['space-y-5']}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user