npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svelte-build-og

v0.3.0

Published

Generate Open Graph images from SvelteKit routes during development and build.

Downloads

25

Readme

svelte-build-og

Generate Open Graph images from ordinary SvelteKit routes. You build the card with your normal components, CSS, fonts, and design tokens; the plugin captures selected routes in Chromium and emits the resulting images with the rest of the application.

Install

pnpm add --save-dev svelte-build-og

Chromium is downloaded automatically on the first capture on machines with a writable browser cache. Read-only and serverless environments need an explicit browser provider.

Configure

Add named inputs in vite.config.ts. A static input is just a route. A dynamic input uses SvelteKit's full-segment [param], [[param]], or [...param] syntax, including matchers, and an entries function to select every image that should exist after the build. Embedded forms such as post-[slug] are not supported.

import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import { og } from "svelte-build-og/vite";

export default defineConfig({
	plugins: [
		sveltekit(),
		og({
			input: {
				home: "/og/home",
				docs: {
					link: "/og/docs/[category]/[slug]",
					entries: () => [
						{ category: "ser", slug: "intro" },
						{ category: "ser", slug: "installation" },
					],
				},
				post: {
					link: "/og/blog/[year]/[...slug]",
					entries: async () => [{ year: "2026", slug: "releases/svelte-build-og" }],
				},
			},
			format: { file: "png", opts: { compressionLevel: 9 } },
			size: { x: 1200, y: 630 },
		}),
	],
});

The default capture concurrency is one. Raise it only when the target environment has enough memory for multiple pages in the shared browser context:

og({
	capture: { concurrency: 2 },
	input: { home: "/og/home" },
});

For Vercel and other serverless environments, install @sparticuz/chromium and use the official adapter instead of relying on Playwright's installer:

import chromium from "@sparticuz/chromium";
import { og, serverless_chromium } from "svelte-build-og/vite";

og({
	browser: serverless_chromium(chromium),
	input: { home: "/og/home" },
});

entries can fill any number of dynamic route layers, including rest parameters such as [...slug]. Each returned object creates one output image at the resolved route plus the selected extension.

The format is a discriminated object, so opts is typed as the corresponding Sharp PNG, WebP, or AVIF options:

format: { file: "webp", opts: { quality: 84, effort: 5 } }

Chromium always captures a PNG first. Sharp only performs the configured output encoding afterward.

Resolve an image

Import resolved from the package root. The plugin generates types from the named inputs, so each name accepts only its own route parameters.

<script lang="ts">
	import { resolved } from "svelte-build-og";

	const image = resolved("docs", { category: "ser", slug: "intro" });
</script>

<img src={image} alt="SER introduction card" />

Static inputs do not take a parameters object:

const image = resolved("home");

resolved respects SvelteKit's configured base and asset paths. It returns a path because that is what <img> expects; Open Graph metadata normally needs an absolute URL, so resolve it against the current page URL:

<script lang="ts">
	import { page } from "$app/state";
	import { resolved } from "svelte-build-og";

	const image = new URL(
		resolved("docs", { category: "ser", slug: "intro" }),
		page.url,
	).href;
</script>

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

For a prerendered application, set SvelteKit's kit.prerender.origin to the production origin so that absolute metadata URLs are generated correctly.

Generated types

The generated declaration lives at .svelte-kit/svelte-build-og/generated.d.ts. Register it through SvelteKit's generated TypeScript configuration so the declaration remains visible without putting generated files in application source:

import { include_og_types } from "svelte-build-og/vite";

const sveltekit_config = {
	kit: {
		typescript: { config: include_og_types },
	},
};

If the application changes SvelteKit's kit.outDir, pass the same directory to sveltekit_out_dir:

og({
	input: {
		home: "/og/home",
	},
	sveltekit_out_dir: ".generated/svelte-kit",
});

The directory is resolved from the Vite root and should remain excluded from version control alongside the rest of SvelteKit's generated output.

On the first Vite start after upgrading from 0.2, build-og removes its old declaration after the replacement has been written. The former default src/.svelte-build-og/generated.d.ts is detected automatically. If 0.2 used a custom types_file, leave that option in place for the first successful 0.3 start so build-og can remove it, then remove the option and the obsolete ignore rule.

Capture lifecycle

In development, generated image paths are served by Vite and captured lazily. Results remain cached until a watched file is added, changed, or removed. During a production build, the plugin starts an internal local Vite server, warms every capture route serially, and waits for Vite's client and SSR dependency requests to settle. A route that fails during cold preparation is retried once after Vite becomes idle. Pages share one browser context and are reused up to the configured concurrency. Capture waits for document.fonts.ready and two animation frames, takes the viewport-sized PNG with animations disabled, encodes the selected format, and emits each image into Vite's client output.

Only routes returned by entries are emitted. The internal renderer uses Vite's serve command, so capture routes should not branch on $app/environment.building or install behavior that exists only in build-specific Vite hooks. Keep them deterministic and make any remote data they need available in the selected mode.

Development

vp install
vp check
vp run test
vp run test:integration
vp pack

Licensed under BSD-3-Clause.