sveltekit-og
repository·main·Indexed 43 days ago
https://github.com/ethercorps/sveltekit-ogA library for dynamically generating Open Graph images in SvelteKit using HTML+CSS or Svelte components without a headless browser. It supports Satori (HTML → SVG → PNG) and Takumi (Rust/WASM) rendering engines, providing ImageResponse and Component Rendering utilities for various deployment targets including Cloudflare Workers, Deno, and Node.js.
What's inside sveltekit-og
- SvelteKit OG is a high-performance utility library for server-side image generation within SvelteKit applications. While primarily used for creating dynamic Open Graph (OG) images for social media previews, it is a generic tool that converts Svelte components or HTML/CSS into high-quality PNGs. It allows you to define a visual template using modern web technologies and render unique images on the fly based on dynamic data or URL parameters.
Key features of SvelteKit OG
mainSvelteKit OG provides several developer-centric features:
- Fast & Lightweight: Runs in edge/serverless environments without a browser instance.
- Easy Styling: Supports standard CSS (Flexbox) and Tailwind CSS.
- Svelte Component Support: You can render actual
.sveltecomponents as image templates. - Typography: Supports custom fonts, Google Fonts, and Emojis.
- Developer Experience: Fully typed with TypeScript and includes a Debug Mode to inspect layout bounding boxes for design fine-tuning.
How SvelteKit OG achieves Zero-Browser Rendering
mainSvelteKit OG avoids the performance overhead of headless browsers (like Puppeteer) by using a two-step rendering pipeline that is compatible with serverless and edge environments (e.g., Vercel Edge, Cloudflare Workers, Netlify functions):
- Satori (Vercel): Converts standard HTML and CSS (Flexbox, Tailwind) into an SVG representation.
- Resvg: A Rust-based library that converts the SVG into the final PNG or JPEG image file.
How fonts work in sveltekit-og
mainTo ensure consistent typography in generated images, the rendering engine (Satori) requires font files as raw binary data (
ArrayBuffer). You cannot use standard CSS@font-facerules.sveltekit-ogprovides three main ways to manage this:GoogleFont: Automatically fetches and caches Google Fonts.CustomFont: Used for local files or remote URLs.resolveFonts: A utility that converts font instances into the required binary data format.
Important: The
resolveFontsPatternFor the standard
ImageResponseengine, you must pass your font instances throughawait resolveFonts([...])before passing the result to thefontsoption.Note: If you are using the Takumi engine, you pass font instances directly to
fontsand skipresolveFonts.import { ImageResponse } from '@ethercorps/sveltekit-og'; import { GoogleFont, resolveFonts } from '@ethercorps/sveltekit-og/fonts'; const font = new GoogleFont('Inter', { weight: 400 }); export const GET = async () => { // Always resolve before passing to ImageResponse const resolvedFonts = await resolveFonts([font]); return new ImageResponse('<div>Hello</div>', { fonts: resolvedFonts }); };Pass dynamic data to Svelte components via props
mainWhen using a Svelte component as the first argument toImageResponse, you can pass dynamic data (like titles, authors, or dates) using the third argument of the constructor. The types for this object are automatically inferred from the props defined in your Svelte component. This parameter is required if your component expects props.Choose a rendering engine for Open Graph generation
mainThe library supports two primary rendering engines for converting HTML/CSS or Svelte components into images:
- Satori (Default): Converts HTML → SVG → PNG. It is based on the Satori engine.
- Takumi: A Rust/WASM engine available via
@ethercorps/sveltekit-og/takumi(v4.3.0+). It is recommended if you need more output formats (such aswebp,jpeg,ico, orsvg) or want to use its built-in font support.
Configure the legacy Rollup plugin
mainIf you are using
sveltekit-og@v4.0.0, you must use therollupWasmplugin. This plugin is located inside therollupOptionsblock of yourvite.config.ts.Warning: This method is deprecated and will be removed in
v5. Migrate to the Vite plugin as soon as possible.import { sveltekit } from '@sveltejs/kit/vite'; import { rollupWasm } from '@ethercorps/sveltekit-og/plugin'; import { defineConfig } from 'vite'; const config = defineConfig({ plugins: [sveltekit()], build: { rollupOptions: { // Add rollupWasm plugin for Cloudflare compatibility plugins: [rollupWasm()] } } }); export default config;Create a new Svelte project with sv
mainUse the
svCLI (powered bysveltejs/cli) to scaffold a new Svelte project. You can either initialize the project in the current directory or specify a new directory name.# create a new project in the current directory npx sv create # create a new project in my-app npx sv create my-appAccess library documentation and usage guides
mainIf you are looking to use the library in your own project, do not use the instructions in this monorepo root. Instead, refer to the package-specific documentation located atpackages/sveltekit-og/README.mdor visit the official documentation website at sveltekit-og.dev.Load assets using Public Absolute URLs
mainThe simplest way to reference assets located in your
staticfolder is to use a full absolute URL. Satori requires an absolute URL (e.g.,https://example.com/logo.png) to fetch the image via HTTP.Implementation: Construct the URL using the
url.originproperty from the SvelteKit request object.Warning for Edge Runtimes: In Edge Runtimes (Cloudflare, Vercel Edge, Deno), using
fetch()to retrieve an asset from your own server viaurl.origincan cause slow cold starts. In these environments, Vite Inline Import (?inline) or Reading Local Assets ($app/server/read) are strongly preferred.import { ImageResponse } from '@ethercorps/sveltekit-og'; import type { RequestHandler } from './$types'; export const GET: RequestHandler = async ({ url }) => { // Construct the absolute URL using the request URL's origin // Assumes logo.png is in the static folder const absoluteUrl = `${url.origin}/logo.png`; const htmlToRender = ` <div tw="flex"> <img src="${absoluteUrl}" width="100" height="100" /> </div> `; return new ImageResponse(htmlToRender, { width: 1200, height: 630 }); };Use local custom fonts with CustomFont
mainTo use
.ttfor.otffiles stored within your project, use theCustomFontclass. This requires a lazy-loading pattern to ensure the file is read only when needed.Implementation Steps
- Import the file: Use the Vite
?urlsuffix (e.g.,import MyFont from './font.ttf?url') to get the build-time path. - Wrap in CustomFont: Pass a function to the
CustomFontconstructor that returns theArrayBuffer. Use SvelteKit's$app/serverreadfunction to retrieve the file.
Warning: On certain adapters like Netlify, Vite's
?urlcombined withreadmay fail. In those cases, use Node'sfsmodule or a public URL.import { CustomFont, resolveFonts } from '@ethercorps/sveltekit-og/fonts'; import { read } from '$app/server'; import RegularFontPath from '$lib/assets/MyFont-Regular.ttf?url'; const myCustomRegular = new CustomFont( 'My Custom Font', () => read(RegularFontPath).arrayBuffer(), { weight: 400 } );- Import the file: Use the Vite
Configure the Rollup Plugin for SvelteKit OG
mainIf you are using
sveltekit-og@v4.0.0or require a Rollup-specific configuration, use therollupWasmplugin within thebuild.rollupOptions.pluginsarray.Deprecation Warning: The Rollup plugin will be deprecated in v5 of SvelteKit OG. Migrate to the Vite plugin if possible.
import { sveltekit } from '@sveltejs/kit/vite'; import { rollupWasm } from '@ethercorps/sveltekit-og/plugin'; const config = { plugins: [sveltekit()], build: { rollupOptions: { plugins: [rollupWasm()] } } }; export default config;