Skip to content

Commit 99da8df

Browse files
authored
Resize and optimize ogimage and favicons (#2980)
1 parent c9ea239 commit 99da8df

File tree

5 files changed

+69
-28
lines changed

5 files changed

+69
-28
lines changed

.changeset/nasty-ways-sip.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": patch
3+
---
4+
5+
Optimize favicons and og:image using the image resizer

packages/gitbook/src/components/SiteLayout/SiteLayout.tsx

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { buildVersion } from '@/lib/build';
1313
import { isSiteIndexable } from '@/lib/seo';
1414

1515
import { GITBOOK_API_PUBLIC_URL, GITBOOK_ASSETS_URL, GITBOOK_ICONS_URL } from '@v2/lib/env';
16+
import { getResizedImageURL } from '@v2/lib/images';
1617
import { ClientContexts } from './ClientContexts';
1718
import { RocketLoaderDetector } from './RocketLoaderDetector';
1819

@@ -96,33 +97,43 @@ export async function generateSiteLayoutViewport(context: GitBookSiteContext): P
9697
}
9798

9899
export async function generateSiteLayoutMetadata(context: GitBookSiteContext): Promise<Metadata> {
99-
const { site, customization, linker } = context;
100+
const { site, customization, linker, imageResizer } = context;
100101
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;
101102

103+
const faviconSize = 48;
104+
const icons = [
105+
{
106+
url: customIcon?.light
107+
? await getResizedImageURL(imageResizer, customIcon.light, {
108+
width: faviconSize,
109+
height: faviconSize,
110+
})
111+
: linker.toAbsoluteURL(
112+
linker.toPathInContent('~gitbook/icon?size=small&theme=light')
113+
),
114+
type: 'image/png',
115+
media: '(prefers-color-scheme: light)',
116+
},
117+
{
118+
url: customIcon?.dark
119+
? await getResizedImageURL(imageResizer, customIcon.dark, {
120+
width: faviconSize,
121+
height: faviconSize,
122+
})
123+
: linker.toAbsoluteURL(
124+
linker.toPathInContent('~gitbook/icon?size=small&theme=dark')
125+
),
126+
type: 'image/png',
127+
media: '(prefers-color-scheme: dark)',
128+
},
129+
];
130+
102131
return {
103132
title: site.title,
104133
generator: `GitBook (${buildVersion()})`,
105134
icons: {
106-
icon: [
107-
{
108-
url:
109-
customIcon?.light ??
110-
linker.toAbsoluteURL(
111-
linker.toPathInContent('~gitbook/icon?size=small&theme=light')
112-
),
113-
type: 'image/png',
114-
media: '(prefers-color-scheme: light)',
115-
},
116-
{
117-
url:
118-
customIcon?.dark ??
119-
linker.toAbsoluteURL(
120-
linker.toPathInContent('~gitbook/icon?size=small&theme=dark')
121-
),
122-
type: 'image/png',
123-
media: '(prefers-color-scheme: dark)',
124-
},
125-
],
135+
icon: icons,
136+
apple: icons,
126137
},
127138
robots: (await isSiteIndexable(context)) ? 'index, follow' : 'noindex, nofollow',
128139
};

packages/gitbook/src/components/SitePage/SitePage.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { PageBody, PageCover } from '@/components/PageBody';
1010
import { getPagePath } from '@/lib/pages';
1111
import { isPageIndexable, isSiteIndexable } from '@/lib/seo';
1212

13+
import { getResizedImageURL } from '@v2/lib/images';
1314
import { PageClientLayout } from './PageClientLayout';
1415
import { type PagePathParams, fetchPageData, getPathnameParam, normalizePathname } from './fetch';
1516

@@ -118,7 +119,7 @@ export async function generateSitePageMetadata(props: SitePageProps): Promise<Me
118119
}
119120

120121
const { page, ancestors } = pageTarget;
121-
const { site, customization, pages, linker } = context;
122+
const { site, customization, pages, linker, imageResizer } = context;
122123

123124
return {
124125
title: [page.title, site.title].filter(Boolean).join(' | '),
@@ -131,8 +132,12 @@ export async function generateSitePageMetadata(props: SitePageProps): Promise<Me
131132
},
132133
openGraph: {
133134
images: [
134-
customization.socialPreview.url ??
135-
linker.toAbsoluteURL(linker.toPathInContent(`~gitbook/ogimage/${page.id}`)),
135+
customization.socialPreview.url
136+
? await getResizedImageURL(imageResizer, customization.socialPreview.url, {
137+
width: 1200,
138+
height: 630,
139+
})
140+
: linker.toAbsoluteURL(linker.toPathInContent(`~gitbook/ogimage/${page.id}`)),
136141
],
137142
},
138143
robots:

packages/gitbook/src/routes/icon.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { notFound } from 'next/navigation';
1+
import { notFound, redirect } from 'next/navigation';
22
import { ImageResponse } from 'next/og';
33

44
import { getEmojiForCode } from '@/lib/emojis';
55
import { tcls } from '@/lib/tailwind';
66
import type { GitBookSiteContext } from '@v2/lib/context';
7+
import { getResizedImageURL } from '@v2/lib/images';
78

89
const SIZES = {
910
/** Size for a favicon */
@@ -25,11 +26,24 @@ const SIZES = {
2526
/**
2627
* Generate an icon for a site content.
2728
*/
28-
export function serveIcon(context: GitBookSiteContext, req: Request) {
29+
export async function serveIcon(context: GitBookSiteContext, req: Request) {
2930
const options = getOptions(req.url);
3031
const size = SIZES[options.size];
3132

3233
const { site, customization } = context;
34+
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;
35+
36+
// If the site has a custom icon, redirect to it
37+
if (customIcon) {
38+
const iconUrl = options.theme === 'light' ? customIcon.light : customIcon.dark;
39+
redirect(
40+
await getResizedImageURL(context.imageResizer, iconUrl, {
41+
width: size.width,
42+
height: size.height,
43+
})
44+
);
45+
}
46+
3347
const contentTitle = site.title;
3448

3549
return new ImageResponse(

packages/gitbook/src/routes/ogimage.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { type PageParams, fetchPageData } from '@/components/SitePage';
77
import { getAssetURL } from '@/lib/assets';
88
import { filterOutNullable } from '@/lib/typescript';
99
import type { GitBookSiteContext } from '@v2/lib/context';
10+
import { getResizedImageURL } from '@v2/lib/images';
1011

1112
const googleFontsMap: { [fontName in CustomizationDefaultFont]: string } = {
1213
[CustomizationDefaultFont.Inter]: 'Inter',
@@ -31,12 +32,17 @@ const googleFontsMap: { [fontName in CustomizationDefaultFont]: string } = {
3132
*/
3233
export async function serveOGImage(baseContext: GitBookSiteContext, params: PageParams) {
3334
const { context, pageTarget } = await fetchPageData(baseContext, params);
34-
const { customization, site, linker } = context;
35+
const { customization, site, linker, imageResizer } = context;
3536
const page = pageTarget?.page;
3637

3738
// If user configured a custom social preview, we redirect to it.
3839
if (customization.socialPreview.url) {
39-
redirect(customization.socialPreview.url);
40+
redirect(
41+
await getResizedImageURL(imageResizer, customization.socialPreview.url, {
42+
width: 1200,
43+
height: 630,
44+
})
45+
);
4046
}
4147

4248
// Compute all text to load only the necessary fonts

0 commit comments

Comments
 (0)