Resize and optimize ogimage and favicons (#2980)

This commit is contained in:
Samy Pessé
2025-03-13 18:45:14 +01:00
committed by GitHub
parent c9ea23919e
commit 99da8df3d1
5 changed files with 69 additions and 28 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
Optimize favicons and og:image using the image resizer
@@ -13,6 +13,7 @@ import { buildVersion } from '@/lib/build';
import { isSiteIndexable } from '@/lib/seo';
import { GITBOOK_API_PUBLIC_URL, GITBOOK_ASSETS_URL, GITBOOK_ICONS_URL } from '@v2/lib/env';
import { getResizedImageURL } from '@v2/lib/images';
import { ClientContexts } from './ClientContexts';
import { RocketLoaderDetector } from './RocketLoaderDetector';
@@ -96,33 +97,43 @@ export async function generateSiteLayoutViewport(context: GitBookSiteContext): P
}
export async function generateSiteLayoutMetadata(context: GitBookSiteContext): Promise<Metadata> {
const { site, customization, linker } = context;
const { site, customization, linker, imageResizer } = context;
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;
const faviconSize = 48;
const icons = [
{
url: customIcon?.light
? await getResizedImageURL(imageResizer, customIcon.light, {
width: faviconSize,
height: faviconSize,
})
: linker.toAbsoluteURL(
linker.toPathInContent('~gitbook/icon?size=small&theme=light')
),
type: 'image/png',
media: '(prefers-color-scheme: light)',
},
{
url: customIcon?.dark
? await getResizedImageURL(imageResizer, customIcon.dark, {
width: faviconSize,
height: faviconSize,
})
: linker.toAbsoluteURL(
linker.toPathInContent('~gitbook/icon?size=small&theme=dark')
),
type: 'image/png',
media: '(prefers-color-scheme: dark)',
},
];
return {
title: site.title,
generator: `GitBook (${buildVersion()})`,
icons: {
icon: [
{
url:
customIcon?.light ??
linker.toAbsoluteURL(
linker.toPathInContent('~gitbook/icon?size=small&theme=light')
),
type: 'image/png',
media: '(prefers-color-scheme: light)',
},
{
url:
customIcon?.dark ??
linker.toAbsoluteURL(
linker.toPathInContent('~gitbook/icon?size=small&theme=dark')
),
type: 'image/png',
media: '(prefers-color-scheme: dark)',
},
],
icon: icons,
apple: icons,
},
robots: (await isSiteIndexable(context)) ? 'index, follow' : 'noindex, nofollow',
};
@@ -10,6 +10,7 @@ import { PageBody, PageCover } from '@/components/PageBody';
import { getPagePath } from '@/lib/pages';
import { isPageIndexable, isSiteIndexable } from '@/lib/seo';
import { getResizedImageURL } from '@v2/lib/images';
import { PageClientLayout } from './PageClientLayout';
import { type PagePathParams, fetchPageData, getPathnameParam, normalizePathname } from './fetch';
@@ -118,7 +119,7 @@ export async function generateSitePageMetadata(props: SitePageProps): Promise<Me
}
const { page, ancestors } = pageTarget;
const { site, customization, pages, linker } = context;
const { site, customization, pages, linker, imageResizer } = context;
return {
title: [page.title, site.title].filter(Boolean).join(' | '),
@@ -131,8 +132,12 @@ export async function generateSitePageMetadata(props: SitePageProps): Promise<Me
},
openGraph: {
images: [
customization.socialPreview.url ??
linker.toAbsoluteURL(linker.toPathInContent(`~gitbook/ogimage/${page.id}`)),
customization.socialPreview.url
? await getResizedImageURL(imageResizer, customization.socialPreview.url, {
width: 1200,
height: 630,
})
: linker.toAbsoluteURL(linker.toPathInContent(`~gitbook/ogimage/${page.id}`)),
],
},
robots:
+16 -2
View File
@@ -1,9 +1,10 @@
import { notFound } from 'next/navigation';
import { notFound, redirect } from 'next/navigation';
import { ImageResponse } from 'next/og';
import { getEmojiForCode } from '@/lib/emojis';
import { tcls } from '@/lib/tailwind';
import type { GitBookSiteContext } from '@v2/lib/context';
import { getResizedImageURL } from '@v2/lib/images';
const SIZES = {
/** Size for a favicon */
@@ -25,11 +26,24 @@ const SIZES = {
/**
* Generate an icon for a site content.
*/
export function serveIcon(context: GitBookSiteContext, req: Request) {
export async function serveIcon(context: GitBookSiteContext, req: Request) {
const options = getOptions(req.url);
const size = SIZES[options.size];
const { site, customization } = context;
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;
// If the site has a custom icon, redirect to it
if (customIcon) {
const iconUrl = options.theme === 'light' ? customIcon.light : customIcon.dark;
redirect(
await getResizedImageURL(context.imageResizer, iconUrl, {
width: size.width,
height: size.height,
})
);
}
const contentTitle = site.title;
return new ImageResponse(
+8 -2
View File
@@ -7,6 +7,7 @@ import { type PageParams, fetchPageData } from '@/components/SitePage';
import { getAssetURL } from '@/lib/assets';
import { filterOutNullable } from '@/lib/typescript';
import type { GitBookSiteContext } from '@v2/lib/context';
import { getResizedImageURL } from '@v2/lib/images';
const googleFontsMap: { [fontName in CustomizationDefaultFont]: string } = {
[CustomizationDefaultFont.Inter]: 'Inter',
@@ -31,12 +32,17 @@ const googleFontsMap: { [fontName in CustomizationDefaultFont]: string } = {
*/
export async function serveOGImage(baseContext: GitBookSiteContext, params: PageParams) {
const { context, pageTarget } = await fetchPageData(baseContext, params);
const { customization, site, linker } = context;
const { customization, site, linker, imageResizer } = context;
const page = pageTarget?.page;
// If user configured a custom social preview, we redirect to it.
if (customization.socialPreview.url) {
redirect(customization.socialPreview.url);
redirect(
await getResizedImageURL(imageResizer, customization.socialPreview.url, {
width: 1200,
height: 630,
})
);
}
// Compute all text to load only the necessary fonts