Skip to content

Repository files navigation

Satori Node

Satori on Node

This is an example node project running Satori on a Node server with Fastify

Why?

Vercel only supports Edge Runtime for its OG library.

Satori gives you only the building block for generating dynamic images on the fly. It only converts HTML and CSS to SVG.

This repo creates SVG from HTML and CSS using Satori, then converts that SVG to PNG using resvg, and then streams that PNG using Fastify

Development

# Clone the repo
git clone https://github.com/yusufff/satori-node
# Install
yarn install
# Run
yarn dev

This will start the development server.

Go to http://localhost:3000/og?text=Hello to see the image.

The source file for the generated image is located at src/routes/og/index.tsx

Production

yarn build:prod
yarn start:prod

This will generate and start a production build.

Examples

You can try out the Vercel's Open Graph (OG) Image Examples

Basic server cache for the generated images

import{renderToImage}from"./render-to-image";importtype{FastifyPluginAsync}from"fastify";importReactfrom"react";import{Readable}from"stream";// Init a cache mapconstcache=newMap<string,{image: Buffer;contentType: string;}>();constog: FastifyPluginAsync=async(fastify,_opts): Promise<void>=>{fastify.get<{Querystring: {text?: string}}>("/",async(_request,reply)=>{consttext=_request.query.text;if(!text){returnreply.code(400).send({error: "Missing text query parameter"});}// Return the cached image if it existsconstcacheHit=cache.get(_request.url);if(cacheHit){conststream=newReadable({read(){this.push(cacheHit.image);this.push(null);},});reply.type(cacheHit.contentType);returnreply.send(stream);}try{constimageRes=awaitrenderToImage(<divstyle={{fontSize: 100,background: "white",width: "100%",height: "100%",display: "flex",textAlign: "center",alignItems: "center",justifyContent: "center",}}>{text}</div>,{width: 1200,height: 600,debug: false,});// Cache the imagecache.set(_request.url,{image: imageRes.image,contentType: imageRes.contentType,});conststream=newReadable({read(){this.push(imageRes.image);this.push(null);},});reply.type(imageRes.contentType);returnreply.send(stream);}catch(err){console.log(err);returnreply.code(500).send({error: "Internal server error"});}});};exportdefaultog;

Google Font Preview

import{renderToImage}from"../og/render-to-image";importtype{FastifyPluginAsync}from"fastify";importfetchfrom"node-fetch";importReactfrom"react";import{Font}from"satori";import{Readable}from"stream";constFontPreview: FastifyPluginAsync=async(fastify,_opts): Promise<void>=>{fastify.get<{Querystring: {font?: string;color?: string;size?: string};}>("/",async(_request,reply)=>{const{ font, color, size }=_request.query;constfontSize=size ? parseInt(size) : 100;if(!font){returnreply.code(400).send({error: "Missing font query parameter"});}try{consturl=newURL("https://www.googleapis.com/webfonts/v1/webfonts");url.searchParams.set("family",font);url.searchParams.set("key",process.env.GCLOUD_API_KEY??"");constfontReq=awaitfetch(url.toString());constfontRes=(awaitfontReq.json())asgoogle.fonts.WebfontList&{error: {code: number};};if(fontRes?.error){returnreply.code(400).send({error: "Invalid font name"});}constfontFamily=fontRes.items[0].family;constfontFile=fontRes.items[0].files.regular;constfontBuffer=awaitfetch(fontFile).then((res)=>res.buffer());constfonts: Font[]=[{name: fontFamily,data: fontBuffer,weight: 400,style: "normal",},];constimageRes=awaitrenderToImage(<divstyle={{fontSize: fontSize,width: "100%",height: "100%",display: "flex",textAlign: "left",color: color??"black",paddingBottom: fontSize*0.2,}}>{fontFamily}</div>,{height: fontSize+fontSize*0.2,debug: false,
fonts,});conststream=newReadable({read(){this.push(imageRes.image);this.push(null);},});reply.type(imageRes.contentType);returnreply.send(stream);}catch(err){console.log(err);returnreply.code(500).send({error: "Internal server error"});}});};exportdefaultFontPreview;

About

A node server running satori (@vercel/og)

Topics

Resources

Stars

7 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages