Skip to content

Commit a3a944d

Browse files
authored
Fix crash during rendering of ogimage for VA sites with default icon (#3347)
1 parent 88a35ed commit a3a944d

File tree

3 files changed

+69
-40
lines changed

3 files changed

+69
-40
lines changed

.changeset/thick-cups-shout.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+
Fix crash during rendering of ogimage for VA sites with default icon.

packages/gitbook/src/routes/icon.tsx

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,19 @@ const SIZES = {
2424
},
2525
};
2626

27+
type RenderIconOptions = {
28+
size: keyof typeof SIZES;
29+
theme: 'light' | 'dark';
30+
};
31+
2732
/**
2833
* Generate an icon for a site content.
2934
*/
3035
export async function serveIcon(context: GitBookSiteContext, req: Request) {
3136
const options = getOptions(req.url);
3237
const size = SIZES[options.size];
3338

34-
const { site, customization } = context;
39+
const { customization } = context;
3540
const customIcon = 'icon' in customization.favicon ? customization.favicon.icon : null;
3641

3742
// If the site has a custom icon, redirect to it
@@ -45,17 +50,45 @@ export async function serveIcon(context: GitBookSiteContext, req: Request) {
4550
);
4651
}
4752

53+
return new ImageResponse(<SiteDefaultIcon context={context} options={options} />, {
54+
width: size.width,
55+
height: size.height,
56+
headers: {
57+
'cache-tag': [
58+
getCacheTag({
59+
tag: 'site',
60+
site: context.site.id,
61+
}),
62+
].join(','),
63+
},
64+
});
65+
}
66+
67+
/**
68+
* Render the icon as a React node.
69+
*/
70+
export function SiteDefaultIcon(props: {
71+
context: GitBookSiteContext;
72+
options: RenderIconOptions;
73+
style?: React.CSSProperties;
74+
tw?: string;
75+
}) {
76+
const { context, options, style, tw } = props;
77+
const size = SIZES[options.size];
78+
79+
const { site, customization } = context;
4880
const contentTitle = site.title;
4981

50-
return new ImageResponse(
82+
return (
5183
<div
52-
tw={tcls(options.theme === 'light' ? 'bg-white' : 'bg-black', size.boxStyle)}
84+
tw={tcls(options.theme === 'light' ? 'bg-white' : 'bg-black', size.boxStyle, tw)}
5385
style={{
5486
width: '100%',
5587
height: '100%',
5688
display: 'flex',
5789
alignItems: 'center',
5890
justifyContent: 'center',
91+
...style,
5992
}}
6093
>
6194
<h2
@@ -70,19 +103,7 @@ export async function serveIcon(context: GitBookSiteContext, req: Request) {
70103
? getEmojiForCode(customization.favicon.emoji)
71104
: contentTitle.slice(0, 1).toUpperCase()}
72105
</h2>
73-
</div>,
74-
{
75-
width: size.width,
76-
height: size.height,
77-
headers: {
78-
'cache-tag': [
79-
getCacheTag({
80-
tag: 'site',
81-
site: context.site.id,
82-
}),
83-
].join(','),
84-
},
85-
}
106+
</div>
86107
);
87108
}
88109

packages/gitbook/src/routes/ogimage.tsx

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ import {
2020
getResizedImageURL,
2121
resizeImage,
2222
} from '@v2/lib/images';
23+
import { SiteDefaultIcon } from './icon';
2324

2425
/**
2526
* Render the OpenGraph image for a site content.
2627
*/
2728
export async function serveOGImage(baseContext: GitBookSiteContext, params: PageParams) {
2829
const { context, pageTarget } = await fetchPageData(baseContext, params);
29-
const { customization, site, linker, imageResizer } = context;
30+
const { customization, site, imageResizer } = context;
3031
const page = pageTarget?.page;
3132

3233
// If user configured a custom social preview, we redirect to it.
@@ -148,34 +149,36 @@ export async function serveOGImage(baseContext: GitBookSiteContext, params: Page
148149
}
149150

150151
const faviconLoader = async () => {
152+
if (customization.header.logo) {
153+
// Don't load the favicon if we have a logo
154+
// as it'll not be used.
155+
return null;
156+
}
157+
158+
const faviconSize = {
159+
width: 48,
160+
height: 48,
161+
};
162+
151163
if ('icon' in customization.favicon)
152164
return (
153165
<img
154-
src={customization.favicon.icon[theme]}
155-
width={40}
156-
height={40}
157-
tw="mr-4"
166+
{...(await fetchImage(customization.favicon.icon[theme], faviconSize))}
167+
{...faviconSize}
158168
alt="Icon"
159169
/>
160170
);
161-
if ('emoji' in customization.favicon)
162-
return (
163-
<span tw="text-4xl mr-4">
164-
{String.fromCodePoint(Number.parseInt(`0x${customization.favicon.emoji}`))}
165-
</span>
166-
);
167-
const iconImage = await fetchImage(
168-
linker.toAbsoluteURL(
169-
linker.toPathInSpace(
170-
`~gitbook/icon?size=medium&theme=${customization.themes.default}`
171-
)
172-
)
173-
);
174-
if (!iconImage) {
175-
throw new Error('Icon image should always be fetchable');
176-
}
177171

178-
return <img {...iconImage} alt="Icon" width={40} height={40} tw="mr-4" />;
172+
return (
173+
<SiteDefaultIcon
174+
context={context}
175+
options={{
176+
size: 'small',
177+
theme,
178+
}}
179+
style={faviconSize}
180+
/>
181+
);
179182
};
180183

181184
const logoLoader = async () => {
@@ -226,9 +229,9 @@ export async function serveOGImage(baseContext: GitBookSiteContext, params: Page
226229
<img {...logo} alt="Logo" tw="h-[60px]" />
227230
</div>
228231
) : (
229-
<div tw="flex">
232+
<div tw="flex flex-row items-center">
230233
{favicon}
231-
<h3 tw="text-4xl my-0 font-bold">{transformText(site.title)}</h3>
234+
<h3 tw="text-4xl ml-4 my-0 font-bold">{transformText(site.title)}</h3>
232235
</div>
233236
)}
234237

0 commit comments

Comments
 (0)