Skip to content

Commit d827b3f

Browse files
codercatdevseniordeveloper
andauthored
feat: OG image generation — workers-og + 4 templates + rawFonts Vite plugin (Track D) (#681)
Dynamic OG image generation on Cloudflare Workers using workers-og + Satori. Infrastructure: - rawFonts Vite plugin: inlines .ttf as Uint8Array at build time (CF Workers have no filesystem) - Inter Bold + Regular v4.1 TTF fonts from official release - Shared og-utils.ts: brand tokens, TYPE_COLORS, font loading, HTML generation (DRY) Endpoints (all SSR, prerender=false): - /api/og/blog.png — title, author, type badge, content-type color coding - /api/og/podcast.png — amber accent, optional episodeNumber - /api/og/author.png — author-focused layout - /api/og/default.png — simpler fallback layout Features: - 1200x630 PNG, dark gradient background, violet accent - Adaptive title font sizing (42/48/56px based on length) - Author initials avatar with gradient - Cache: 1 day browser, 7 day edge (public, max-age=86400, s-maxage=604800) SocialMeta.astro component wires og:image URLs into page meta tags. Co-authored-by: seniordeveloper <seniordeveloper@miriad.systems>
1 parent 84fe5c2 commit d827b3f

File tree

10 files changed

+646
-11
lines changed

10 files changed

+646
-11
lines changed

apps/web/astro.config.mjs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,39 @@ import cloudflare from "@astrojs/cloudflare";
33
import react from "@astrojs/react";
44
import sanity from "@sanity/astro";
55
import tailwindcss from "@tailwindcss/vite";
6+
import fs from "node:fs";
7+
import path from "node:path";
68

79
// Sanity config — dataset comes from env var (set by wrangler vars or .env)
810
// In astro.config.mjs, .env files are NOT loaded — use process.env
911
const sanityProjectId = process.env.SANITY_PROJECT_ID || "hfh83o0w";
1012
const sanityDataset = process.env.SANITY_DATASET || "production";
1113

14+
/**
15+
* Vite plugin to inline font files as Uint8Array at build time.
16+
* Required for OG image generation on CF Workers (no filesystem access).
17+
*/
18+
function rawFonts(extensions) {
19+
return {
20+
name: "vite-plugin-raw-fonts",
21+
enforce: "pre",
22+
resolveId(id, importer) {
23+
if (extensions.some((ext) => id.includes(ext))) {
24+
if (id.startsWith(".")) {
25+
return path.resolve(path.dirname(importer), id);
26+
}
27+
return id;
28+
}
29+
},
30+
load(id) {
31+
if (extensions.some((ext) => id.includes(ext))) {
32+
const buffer = fs.readFileSync(id);
33+
return `export default new Uint8Array([${Array.from(buffer).join(",")}]);`;
34+
}
35+
},
36+
};
37+
}
38+
1239
export default defineConfig({
1340
output: "server",
1441
adapter: cloudflare({
@@ -31,6 +58,11 @@ export default defineConfig({
3158
react(),
3259
],
3360
vite: {
34-
plugins: [tailwindcss()],
61+
plugins: [tailwindcss(), rawFonts([".ttf", ".otf"])],
62+
assetsInclude: ["**/*.wasm"],
63+
assetsExclude: ["**/*.ttf", "**/*.otf"],
64+
ssr: {
65+
external: ["buffer", "path", "fs"].map((i) => `node:${i}`),
66+
},
3567
},
3668
});

apps/web/package-lock.json

Lines changed: 173 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)