#5613 Optimise social images by utilising next image api. (#5997)

* #5613 Optimise social images by utilising next image api.

* removed unused import

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
Jeroen Reumkens 2022-12-13 22:22:38 +01:00 committed by GitHub
parent 61e6f76bc6
commit 9eb52bbfb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 791 deletions

View File

@ -61,7 +61,7 @@
"@stripe/stripe-js": "^1.35.0",
"@tanstack/react-query": "^4.3.9",
"@vercel/edge-functions-ui": "^0.2.1",
"@vercel/og": "^0.0.19",
"@vercel/og": "^0.0.21",
"accept-language-parser": "^1.5.0",
"async": "^3.2.4",
"bcryptjs": "^2.4.3",

View File

@ -53,6 +53,8 @@ export default async function handler(req: NextApiRequest) {
interFontMedium,
]);
const ogConfig = {
width: 1200,
height: 630,
fonts: [
{ name: "inter", data: interFontData, weight: 400 },
{ name: "inter", data: interFontMediumData, weight: 500 },
@ -71,7 +73,7 @@ export default async function handler(req: NextApiRequest) {
meetingImage: searchParams.get("meetingImage"),
imageType,
});
return new ImageResponse(
const img = new ImageResponse(
(
<Meeting
title={title}
@ -80,7 +82,9 @@ export default async function handler(req: NextApiRequest) {
/>
),
ogConfig
);
) as { body: Buffer };
return new Response(img.body, { status: 200 });
}
case "app": {
const { name, description, slug } = appSchema.parse({
@ -89,7 +93,11 @@ export default async function handler(req: NextApiRequest) {
slug: searchParams.get("slug"),
imageType,
});
return new ImageResponse(<App name={name} description={description} slug={slug} />, ogConfig);
const img = new ImageResponse(<App name={name} description={description} slug={slug} />, ogConfig) as {
body: Buffer;
};
return new Response(img.body, { status: 200 });
}
case "generic": {
@ -99,7 +107,11 @@ export default async function handler(req: NextApiRequest) {
imageType,
});
return new ImageResponse(<Generic title={title} description={description} />, ogConfig);
const img = new ImageResponse(<Generic title={title} description={description} />, ogConfig) as {
body: Buffer;
};
return new Response(img.body, { status: 200 });
}
default:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -39,8 +39,11 @@ const joinMultipleNames = (names: string[] = []) => {
* 4. Team event (round robin) http://localhost:3000/api/social/og/image?type=meeting&title=Round%20Robin%20Seeded%20Team%20Event&meetingProfileName=Seeded%20Team
* 5. Dynamic collective (2 persons) http://localhost:3000/api/social/og/image?type=meeting&title=15min&meetingProfileName=Team%20Pro%20Example,%20Pro%20Example&names=Team%20Pro%20Example&names=Pro%20Example&usernames=teampro&usernames=pro
*/
export const constructMeetingImage = ({ title, users = [], profile }: MeetingImageProps): string => {
return [
export const constructMeetingImage = (
{ title, users = [], profile }: MeetingImageProps,
encodeUri = true
): string => {
const url = [
`?type=meeting`,
`&title=${encodeURIComponent(title)}`,
`&meetingProfileName=${encodeURIComponent(profile.name)}`,
@ -49,29 +52,35 @@ export const constructMeetingImage = ({ title, users = [], profile }: MeetingIma
`${users.map((user) => `&usernames=${encodeURIComponent(user.username)}`).join("")}`,
// Joining a multiline string for readability.
].join("");
return encodeUri ? encodeURIComponent(url) : url;
};
/**
* Test url:
* http://localhost:3000/api/social/og/image?type=app&name=Huddle01&slug=/api/app-store/huddle01video/icon.svg&description=Huddle01%20is%20a%20new%20video%20conferencing%20software%20native%20to%20Web3%20and%20is%20comparable%20to%20a%20decentralized%20version%20of%20Zoom.%20It%20supports%20conversations%20for...
*/
export const constructAppImage = ({ name, slug, description }: AppImageProps): string => {
return [
export const constructAppImage = ({ name, slug, description }: AppImageProps, encodeUri = true): string => {
const url = [
`?type=app`,
`&name=${encodeURIComponent(name)}`,
`&slug=${encodeURIComponent(slug)}`,
`&description=${encodeURIComponent(description)}`,
// Joining a multiline string for readability.
].join("");
return encodeUri ? encodeURIComponent(url) : url;
};
export const constructGenericImage = ({ title, description }: GenericImageProps) => {
return [
export const constructGenericImage = ({ title, description }: GenericImageProps, encodeUri = true) => {
const url = [
`?type=generic`,
`&title=${encodeURIComponent(title)}`,
`&description=${encodeURIComponent(description)}`,
// Joining a multiline string for readability.
].join("");
return encodeUri ? encodeURIComponent(url) : url;
};
const Wrapper = ({

View File

@ -38,7 +38,13 @@ export const POWERED_BY_URL = `${WEBSITE_URL}/?utm_source=embed&utm_medium=power
export const DOCS_URL = "https://docs.cal.com";
export const DEVELOPER_DOCS = "https://developer.cal.com";
export const SEO_IMG_DEFAULT = `${WEBSITE_URL}/og-image.png`;
export const SEO_IMG_OGIMG = `${CAL_URL}/api/social/og/image`;
// The Dynamic OG Image is passed through Next's Image API to further optimize it.
// This results in a 80% smaller image 🤯. It is however important that for the query
// parameters you pass to the /api/social/og/image endpoint, you wrap them in encodeURIComponent
// as well, otherwise the URL won't be valid.
export const SEO_IMG_OGIMG = `${CAL_URL}/_next/image?w=1200&q=100&url=${encodeURIComponent(
"/api/social/og/image"
)}`;
export const SEO_IMG_OGIMG_VIDEO = `${WEBSITE_URL}/video-og-image.png`;
export const IS_STRIPE_ENABLED = !!(
process.env.STRIPE_CLIENT_ID &&

834
yarn.lock

File diff suppressed because it is too large Load Diff