Skip to content

Commit cf4b124

Browse files
SamyPesseemmerich
andauthored
Optimize performances for reading revisions (GitbookIO#251)
* Optimize read of revisions with metadata=false when possible * Format * Fix * Update src/components/AdminToolbar/AdminToolbar.tsx Co-authored-by: Steven H <shne24@gmail.com> --------- Co-authored-by: Steven H <shne24@gmail.com>
1 parent 221d85c commit cf4b124

File tree

5 files changed

+93
-27
lines changed

5 files changed

+93
-27
lines changed

bun.lockb

0 Bytes
Binary file not shown.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
],
2020
"dependencies": {
2121
"@geist-ui/icons": "^1.0.2",
22-
"@gitbook/api": "^0.35.0",
22+
"@gitbook/api": "^0.36.0",
2323
"@radix-ui/react-checkbox": "^1.0.4",
2424
"@radix-ui/react-popover": "^1.0.7",
2525
"@sentry/nextjs": "^7.94.1",

packages/react-contentkit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"main": "./src/index.ts",
44
"dependencies": {
55
"classnames": "^2.5.1",
6-
"@gitbook/api": "^0.35.0",
6+
"@gitbook/api": "^0.36.0",
77
"assert-never": "^1.2.1"
88
},
99
"peerDependencies": {

src/components/AdminToolbar/AdminToolbar.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ async function ChangeRequestToolbar(props: { spaceId: string; changeRequestId: s
7676
async function RevisionToolbar(props: { spaceId: string; revisionId: string }) {
7777
const { spaceId, revisionId } = props;
7878

79-
const revision = await getRevision(spaceId, revisionId);
79+
const revision = await getRevision(spaceId, revisionId, {
80+
metadata: false,
81+
});
8082

8183
return (
8284
<ToolbarButton href={revision.urls.app}>

src/lib/api.ts

Lines changed: 88 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,16 @@ export interface ContentTarget {
4747
*
4848
* We don't cache for more than this to ensure we don't use too much storage and keep the cache small.
4949
*/
50-
const immutableCacheTtl = {
50+
const immutableCacheTtl_7days = {
5151
revalidateBefore: 24 * 60 * 60,
5252
ttl: 7 * 24 * 60 * 60,
5353
tags: [],
5454
};
55+
const immutableCacheTtl_1day = {
56+
revalidateBefore: 60 * 60,
57+
ttl: 24 * 60 * 60,
58+
tags: [],
59+
};
5560

5661
const apiSyncStorage = new AsyncLocalStorage<GitBookAPI>();
5762

@@ -285,18 +290,46 @@ export const getSpaceIntegrationScripts = cache(
285290
},
286291
);
287292

293+
interface GetRevisionOptions {
294+
/**
295+
* Whether to fetch the Git metadata of the pages.
296+
* Passing `false` can optimize performances and generally should be when the Git sync is disabled (we don't need to display "Edit git" on the page).
297+
*
298+
* These options don't impact the cache key and it means revisions can be shared between different fetches with different metadata options.
299+
*/
300+
metadata: boolean;
301+
}
302+
288303
/**
289304
* Get a revision by its ID.
290305
*/
291306
export const getRevision = cache(
292307
'api.getRevision',
293-
async (spaceId: string, revisionId: string, options: CacheFunctionOptions) => {
294-
const response = await api().spaces.getRevisionById(spaceId, revisionId, {
295-
...noCacheFetchOptions,
296-
signal: options.signal,
297-
});
308+
async (
309+
spaceId: string,
310+
revisionId: string,
311+
fetchOptions: GetRevisionOptions,
312+
options: CacheFunctionOptions,
313+
) => {
314+
const response = await api().spaces.getRevisionById(
315+
spaceId,
316+
revisionId,
317+
{
318+
metadata: fetchOptions.metadata,
319+
},
320+
{
321+
...noCacheFetchOptions,
322+
signal: options.signal,
323+
},
324+
);
298325

299-
return cacheResponse(response, immutableCacheTtl);
326+
return cacheResponse(
327+
response,
328+
fetchOptions.metadata ? immutableCacheTtl_7days : immutableCacheTtl_1day,
329+
);
330+
},
331+
{
332+
extractArgs: (args) => [args[1], args[2]],
300333
},
301334
);
302335

@@ -305,17 +338,32 @@ export const getRevision = cache(
305338
*/
306339
export const getRevisionPages = cache(
307340
'api.getRevisionPages.v3',
308-
async (spaceId: string, revisionId: string, options: CacheFunctionOptions) => {
309-
const response = await api().spaces.listPagesInRevisionById(spaceId, revisionId, {
310-
...noCacheFetchOptions,
311-
signal: options.signal,
312-
});
341+
async (
342+
spaceId: string,
343+
revisionId: string,
344+
fetchOptions: GetRevisionOptions,
345+
options: CacheFunctionOptions,
346+
) => {
347+
const response = await api().spaces.listPagesInRevisionById(
348+
spaceId,
349+
revisionId,
350+
{
351+
metadata: fetchOptions.metadata,
352+
},
353+
{
354+
...noCacheFetchOptions,
355+
signal: options.signal,
356+
},
357+
);
313358

314359
return cacheResponse(response, {
315-
...immutableCacheTtl,
360+
...(fetchOptions.metadata ? immutableCacheTtl_7days : immutableCacheTtl_1day),
316361
data: response.data.pages,
317362
});
318363
},
364+
{
365+
extractArgs: (args) => [args[1], args[2]],
366+
},
319367
);
320368

321369
/**
@@ -336,19 +384,21 @@ export const getRevisionPageByPath = cache(
336384
spaceId,
337385
revisionId,
338386
encodedPath,
339-
{},
387+
{
388+
metadata: false,
389+
},
340390
{
341391
...noCacheFetchOptions,
342392
signal: options.signal,
343393
},
344394
);
345395

346-
return cacheResponse(response, immutableCacheTtl);
396+
return cacheResponse(response, immutableCacheTtl_7days);
347397
} catch (error) {
348398
if ((error as GitBookAPIError).code === 404) {
349399
return {
350400
data: null,
351-
...immutableCacheTtl,
401+
...immutableCacheTtl_7days,
352402
};
353403
}
354404

@@ -365,16 +415,24 @@ export const getRevisionFile = cache(
365415
async (spaceId: string, revisionId: string, fileId: string, options: CacheFunctionOptions) => {
366416
try {
367417
const response = await (async () => {
368-
return api().spaces.getFileInRevisionById(spaceId, revisionId, fileId, {
369-
...noCacheFetchOptions,
370-
signal: options.signal,
371-
});
418+
return api().spaces.getFileInRevisionById(
419+
spaceId,
420+
revisionId,
421+
fileId,
422+
{
423+
metadata: false,
424+
},
425+
{
426+
...noCacheFetchOptions,
427+
signal: options.signal,
428+
},
429+
);
372430
})();
373431

374-
return cacheResponse(response, immutableCacheTtl);
432+
return cacheResponse(response, immutableCacheTtl_7days);
375433
} catch (error: any) {
376434
if (error instanceof GitBookAPIError && error.code === 404) {
377-
return { data: null, ...immutableCacheTtl };
435+
return { data: null, ...immutableCacheTtl_7days };
378436
}
379437

380438
throw error;
@@ -399,7 +457,7 @@ export const getDocument = cache(
399457
...noCacheFetchOptions,
400458
},
401459
);
402-
return cacheResponse(response, immutableCacheTtl);
460+
return cacheResponse(response, immutableCacheTtl_7days);
403461
},
404462
);
405463

@@ -517,7 +575,13 @@ export async function getSpaceContentData(pointer: ContentPointer) {
517575
spaceId: pointer.spaceId,
518576
revisionId: changeRequest?.revision ?? pointer.revisionId ?? space.revision,
519577
};
520-
const [pages] = await Promise.all([getRevisionPages(space.id, contentTarget.revisionId)]);
578+
const [pages] = await Promise.all([
579+
getRevisionPages(space.id, contentTarget.revisionId, {
580+
// We only care about the Git metadata when the Git sync is enabled
581+
// otherwise we can optimize performance by not fetching it
582+
metadata: !!space.gitSync,
583+
}),
584+
]);
521585

522586
return {
523587
space,

0 commit comments

Comments
 (0)