Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
November 10, 2022 03:17 pm GMT

Create OG images for your blog with Next.js

At the same time I released the new design for this blog using Next.js, Vercel announced a new library to generate OpenGraph (OG) images. You know, these images you can see when posting some links on Twitter.

Since my blog posts had a cover image associated, it sounded natural to me to use this image. But I often wonder if it was worth it to generate an image with additional content such as the post title or its date. It was pretty complicated to generate an image.

Fortunately, Vercels OG library now makes it much easier. Lets see how by implementing OG image generation for an imaginary blog.

If you are curious about Next.js and want to learn it, check out by book Serverless Web Applications with React and Next.js.

If you prefer video content, I created a short video with the content of this post:

@vercel/og, satori, and Edge functions

Generating OG images is made possible by the @vercel/og library, itself relying on satori (also made by Vercel). This package allows you to create an image from HTML and CSS code (using JSX). @vercel/og adds a layer to make it easier to use, for instance by loading a default font so you dont have to.

On the client, such generation does not sound complicated, and weve known how to do it for a long time using a canvas element. But on the server, you had to start a headless Chrome browser, which was complex and expensive. satori doesnt work that way, and can generate images efficiently on the client, or in serverless functions.

Even better, it can run on Edge functions, and that is what @vercel/og does. Edge functions are a special kind of serverless functions, that are free from all the classic Node.js runtime features. You can only use the basic JavaScript features, from the V8 runtime, so Edge functions comes with some limitations, but are extremely fast, and their execution cheaper.

Generate an image with @vercel/og

You can follow this tutorial on any Next.js project. Ill show how to start from an empty Next.js application, just generated with the command:

$ yarn create next-app hello-og --typescript

In this project, well use a serverless function to generate OG images, accessible at the endpoint /api/og. Lets create it in a new /pages/api/og.tsx file.

import { NextRequest, NextResponse } from 'next/server'export const config = {  runtime: 'experimental-edge',}const handle = (req: NextRequest) => {  return NextResponse.json({ hello: true })}export default handle

If you are used to serverless functions in Next.js, you might notice some differences:

  1. The exported config object. Here we tell Next.js that this function is an Edge function.
  2. The req parameter does not have the NextApiRequest type, but NextRequest. This is also because its an Edge function.
  3. We return a response (instead of using a res object passed as parameter), of type NextResponse.

Still, if you run the application and call the endpoint, you will get the expected JSON result, as with any classic function:

$ curl http://localhost:3000/api/og{"hello":true}

Now lets update this function to return an image using @vercel/og. We first need to add the dependency to our project with yarn add @vercel/og. Then we can generate a basic image containing the text Hello World!:

import { ImageResponse } from '@vercel/og'// ...const handle = (req: NextRequest) => {  return new ImageResponse(    <div>Hello World!</div>,    // 1200x628 seems to be the right dimensions to use for OG images.    { width: 1200, height: 628 },  )}

With these three lines of code returning an ImageResponse, we generate an image from React code. That sounds easy, right? You probably think this is great, I can use all my React components! Well, its not that easy .

Even though we use JSX here, its important to understand that its just a shorthand offered by satori (which seems to use React, but not React-DOM). The JSX code you write here has some constraints:

  • Not all CSS properties are supported,
  • Only flex layout is supported, and each element with multiple children must explicitely use (display: flex),
  • You cant use script or link elements, etc.

Knowing these constraints, we can still do a lot. A feature I love: you can use TailwindCSS classes natively, using the tw prop on elements (instead of className). If you prefer, you can use the classic style prop to specify CSS properties.

Lets assume we want to display a post title, an author name, and a date that well receive from query parameters. To get these parameters, we cant use req.query: in Edge functions, we have to use req.url, that we can parse using the URL class:

const handle = (req: NextRequest) => {  const { searchParams } = new URL(req.url)  const title = searchParams.get('title') || 'No post title'  const author = searchParams.get('author') || 'Anonymous'  const date = new Date(searchParams.get('date') || '2022-11-05T12:00:00.000Z')

And then, we can use these parameters to add them to the image, with some TailwindCSS classes to make everything a bit more beautiful:

  return new ImageResponse(    (      <div tw="flex w-full h-full flex-col justify-end bg-slate-200 items-stretch">        <div tw="flex flex-col bg-white p-8">          <div tw="text-5xl mb-4">{title}</div>          <div tw="text-2xl">            {author +              '  ' +              date.toLocaleDateString('en-US', { dateStyle: 'long' })}          </div>        </div>      </div>    ),    { width: 1200, height: 628 }  )}

Here is what this first version of our OG image looks like, with some parameters:

First version of our OG image

An image inside the image

This is nice, but it misses the most important thing we want on it: the cover image. Lets add a cover parameter, and use it in an img element:

const handle = (req: NextRequest) => {  const { searchParams, host, protocol } = new URL(req.url)  // ...  const cover = `${protocol}//${host}${    searchParams.get('cover') || '/cover.jpg'  }`  return new ImageResponse(    (      <div tw="flex w-full h-full flex-col justify-end bg-slate-200 items-stretch">        <img          src={cover}          alt=""          tw="flex-1 w-full h-full"          style={{ objectFit: 'cover', objectPosition: 'center' }}        />        {/* ... */}      </div>    ),    { width: 1200, height: 628 }  )}

(To run the example, go get an image on Unsplash and put it in public/cover.jpg.)

Note how we use the host and protocol attributes from the requests URL, as we need to use absolute URLs for img elements.

Second version of our OG image

This second version is much more satisfying until we deploy it on Vercel. After deployment, if you call try to generate an image, you might get a blank image. In the Vercel logs, youll see this kind of error:

The error log on Vercel

It isnt obvious, but the issue comes from the cover image we want to include, which seems too big for @vercel/og at the time Im writing this post. We could choose to use a smaller image, but its pretty annoying

Good news, Next.js already provides an easy way to resize images. When using the next/image component, Next.js uses an endpoint at /_next/image. While we can not use the component, we can use the endpoint!

const cover = `${protocol}//${host}/_next/image?url=${encodeURIComponent(  searchParams.get('cover') || '/cover.jpg')}&w=1200&q=75`

Add OG image to your pages

Now that we know how to generate our image, we can use it in the meta tags of the page headers. You can find the complete list of meta tags you need to define in Twitter documentation. I like using a custom component I built in many projects of mine: SeoHeaders.

If you are adding OG images to a Next.js blog, I assume you already have a component in which you know the post title, author, date, and cover image. You can build the OG image URL:

// It must be an absolute URL, so I use an// environment variable for the base URL.const imageUrl =  `${process.env.NEXT_PUBLIC_BASE_URL}/api/og?` +  `title=${encodeURIComponent(title)}` +  `&author=${encodeURIComponent(author)}` +  `&cover=${encodeURIComponent(cover)}` +  `&date=${date}`

Then, you can pass this URL to the SeoHeaders component:

<SeoHeaders  title={title}  description=""  author={author}  twitterAuthor=""  twitterSite=""  url={process.env.NEXT_PUBLIC_BASE_URL}  imageUrl={imageUrl}/>

Or, if you add the meta tags by yourself:

<meta property="og:image" content={imageUrl} /><meta name="twitter:image" content={imageUrl} />

Note that so that the image is used in social media, you need to specify the other tags: og:type, twitter:card, etc.

This concludes this tutorial about generating and using OG images in a Next.js application! Our image is pretty minimalist, but here are a few ideas if you want to improve it:

  • Play with opacity options (using TailwindCSS class bg-opacity-50 for instance) instead of having a white background for the text.
  • Add the authors avatar (using a second image).
  • Add the description to the image, or an excerpt of it.
  • If your blog allows comments or likes, you can add some counter to the image.

Youll find the complete source code of the example Next.js application on this GitHub repo. Dont forget to check out the documentation of Vercels OG Image Generation.

This post was first posted on my blog: Create OG images for your blog with Next.js.

Cover photo by Noman Shahid.


Original Link: https://dev.to/scastiel/create-og-images-for-your-blog-with-nextjs-d5f

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To