mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-21 01:53:26 +00:00
Make sure to use the correct version for adaptive content (#3487)
Co-authored-by: Nicolas Dorseuil <nicolas@gitbook.io>
This commit is contained in:
@@ -14,6 +14,9 @@ const nextConfig = {
|
||||
dynamic: 3600, // 1 hour
|
||||
static: 3600, // 1 hour
|
||||
},
|
||||
|
||||
// Since content is fully static, we don't want to fetch on hover again
|
||||
optimisticClientCache: false,
|
||||
},
|
||||
|
||||
env: {
|
||||
|
||||
@@ -3,15 +3,19 @@
|
||||
import type { CustomizationThemeMode, SiteExternalLinksTarget } from '@gitbook/api';
|
||||
import { ThemeProvider } from 'next-themes';
|
||||
import type React from 'react';
|
||||
import { useClearRouterCache } from '../hooks/useClearRouterCache';
|
||||
import { LinkSettingsContext } from '../primitives';
|
||||
|
||||
export function ClientContexts(props: {
|
||||
nonce?: string;
|
||||
forcedTheme: CustomizationThemeMode | undefined;
|
||||
externalLinksTarget: SiteExternalLinksTarget;
|
||||
contextId: string | undefined;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { children, forcedTheme, externalLinksTarget } = props;
|
||||
const { children, forcedTheme, externalLinksTarget, contextId } = props;
|
||||
|
||||
useClearRouterCache(contextId);
|
||||
|
||||
/**
|
||||
* A bug in ThemeProvider is causing the nonce to be included incorrectly
|
||||
|
||||
@@ -9,12 +9,11 @@ import { AdminToolbar } from '@/components/AdminToolbar';
|
||||
import { CookiesToast } from '@/components/Cookies';
|
||||
import { LoadIntegrations } from '@/components/Integrations';
|
||||
import { SpaceLayout } from '@/components/SpaceLayout';
|
||||
import { buildVersion } from '@/lib/build';
|
||||
import { isSiteIndexable } from '@/lib/seo';
|
||||
|
||||
import type { VisitorAuthClaims } from '@/lib/adaptive';
|
||||
import { buildVersion } from '@/lib/build';
|
||||
import { GITBOOK_API_PUBLIC_URL, GITBOOK_ASSETS_URL, GITBOOK_ICONS_URL } from '@/lib/env';
|
||||
import { getResizedImageURL } from '@/lib/images';
|
||||
import { isSiteIndexable } from '@/lib/seo';
|
||||
import { ClientContexts } from './ClientContexts';
|
||||
import { RocketLoaderDetector } from './RocketLoaderDetector';
|
||||
|
||||
@@ -50,6 +49,7 @@ export async function SiteLayout(props: {
|
||||
<NuqsAdapter>
|
||||
<ClientContexts
|
||||
nonce={nonce}
|
||||
contextId={context.contextId}
|
||||
forcedTheme={
|
||||
forcedTheme ??
|
||||
(customization.themes.toggeable ? undefined : customization.themes.default)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
'use client';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
// We cannot use a ref here because the contextId gets reset on navigation
|
||||
// Probably because of this bug https://github.com/vercel/next.js/issues/67542
|
||||
let previousContextId: string | undefined;
|
||||
|
||||
/**
|
||||
* A custom hook that clears the router cache on contextId change.
|
||||
* This is useful for ensuring that the router does not cache stale data for adaptive content.
|
||||
*/
|
||||
export function useClearRouterCache(contextId: string | undefined) {
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
if (previousContextId === undefined) {
|
||||
// On the first run, we set the previousContextId to the current contextId
|
||||
previousContextId = contextId;
|
||||
return; // Skip the first run to avoid unnecessary reload
|
||||
}
|
||||
// Initially, previousContextId will be undefined, so we only clear the cache
|
||||
// if contextId has changed from a defined value to a new value.
|
||||
// This prevents unnecessary cache clearing on the first render.
|
||||
if (contextId !== previousContextId && previousContextId !== undefined) {
|
||||
previousContextId = contextId;
|
||||
// Trigger a full reload to clear the in-memory cache
|
||||
router.refresh(); // This will clear the cache and re-fetch the data
|
||||
}
|
||||
}, [contextId, router]);
|
||||
}
|
||||
@@ -123,11 +123,15 @@ export const Link = React.forwardRef(function Link(
|
||||
);
|
||||
}
|
||||
|
||||
// Not sure why yet, but it seems necessary to force prefetch to true
|
||||
// default behavior doesn't seem to properly use the client router cache.
|
||||
const _prefetch = prefetch === null || prefetch === undefined ? true : prefetch;
|
||||
|
||||
return (
|
||||
<NextLink
|
||||
ref={ref}
|
||||
href={href}
|
||||
prefetch={prefetch}
|
||||
prefetch={_prefetch}
|
||||
className={tcls(...forwardedClassNames, className)}
|
||||
{...domProps}
|
||||
onClick={onClick}
|
||||
|
||||
@@ -44,6 +44,7 @@ export type SiteURLData = Pick<
|
||||
| 'siteSection'
|
||||
| 'siteBasePath'
|
||||
| 'basePath'
|
||||
| 'contextId'
|
||||
> & {
|
||||
/**
|
||||
* Identifier used for image resizing.
|
||||
@@ -123,6 +124,9 @@ export type GitBookSiteContext = GitBookSpaceContext & {
|
||||
|
||||
/** Scripts to load for the site. */
|
||||
scripts: SiteIntegrationScript[];
|
||||
|
||||
/** Context ID used by adaptive content. It represents an unique identifier for the authentication context */
|
||||
contextId?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -200,6 +204,7 @@ export async function fetchSiteContextByURLLookup(
|
||||
shareKey: data.shareKey,
|
||||
changeRequest: data.changeRequest,
|
||||
revision: data.revision,
|
||||
contextId: data.contextId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -217,6 +222,7 @@ export async function fetchSiteContextByIds(
|
||||
shareKey: string | undefined;
|
||||
changeRequest: string | undefined;
|
||||
revision: string | undefined;
|
||||
contextId?: string;
|
||||
}
|
||||
): Promise<GitBookSiteContext> {
|
||||
const { dataFetcher } = baseContext;
|
||||
@@ -314,6 +320,7 @@ export async function fetchSiteContextByIds(
|
||||
structure: siteStructure,
|
||||
sections,
|
||||
scripts,
|
||||
contextId: ids.contextId,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +249,7 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
shareKey: siteURLData.shareKey,
|
||||
apiToken: siteURLData.apiToken,
|
||||
imagesContextId: imagesContextId,
|
||||
contextId: siteURLData.contextId,
|
||||
};
|
||||
|
||||
const requestHeaders = new Headers(request.headers);
|
||||
@@ -328,6 +329,12 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
response.headers.set('x-gitbook-route-type', routeType);
|
||||
response.headers.set('x-gitbook-route-site', siteURLWithoutProtocol);
|
||||
|
||||
// When we use adaptive content, we want to ensure that the cache is not used at all on the client side.
|
||||
// Vercel already set this header, this is needed in OpenNext.
|
||||
if (siteURLData.contextId) {
|
||||
response.headers.set('cache-control', 'public, max-age=0, must-revalidate');
|
||||
}
|
||||
|
||||
return writeResponseCookies(response, cookies);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user