From 38f811a24e9611c53105931399a4de9625923817 Mon Sep 17 00:00:00 2001 From: Yasutake Yohei Date: Sat, 4 Jul 2026 23:20:31 +0900 Subject: og画像: タイトルハッシュによるキャッシュで再生成をスキップ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/og/[slug].png.ts | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/pages/og/[slug].png.ts b/src/pages/og/[slug].png.ts index 2b95898..1047647 100644 --- a/src/pages/og/[slug].png.ts +++ b/src/pages/og/[slug].png.ts @@ -1,6 +1,12 @@ import satori from "satori"; import { Resvg } from "@resvg/resvg-js"; -import { readFileSync, existsSync, readdirSync } from "node:fs"; +import { + readFileSync, + existsSync, + readdirSync, + writeFileSync, + mkdirSync, +} from "node:fs"; import path from "node:path"; const contentDir = "src/content/docs"; @@ -136,6 +142,29 @@ export async function GET({ params }: { params: { slug: string } }) { title = `${reiwa}${month}定例会`; } + // Check cache: if title hash matches, return cached PNG + const distDir = path.join(process.cwd(), "dist", "og"); + const cacheFile = path.join(distDir, `${slug}.png`); + const cacheJsonPath = path.join(distDir, ".og-cache.json"); + + let cache: Record = {}; + if (existsSync(cacheJsonPath)) { + cache = JSON.parse(readFileSync(cacheJsonPath, "utf-8")); + } + + const { createHash } = await import("node:crypto"); + const titleHash = createHash("md5").update(title).digest("hex"); + + if (existsSync(cacheFile) && cache[slug] === titleHash) { + const cachedBuffer = readFileSync(cacheFile); + return new Response(cachedBuffer, { + headers: { + "Content-Type": "image/png", + "Cache-Control": "public, max-age=31536000, immutable", + }, + }); + } + const svg = await satori( { type: "div", @@ -264,6 +293,12 @@ export async function GET({ params }: { params: { slug: string } }) { const resvg = new Resvg(svg, { fitTo: { mode: "width", value: 1200 } }); const pngBuffer = resvg.render().asPng(); + // Save to cache + if (!existsSync(distDir)) mkdirSync(distDir, { recursive: true }); + writeFileSync(cacheFile, pngBuffer); + cache[slug] = titleHash; + writeFileSync(cacheJsonPath, JSON.stringify(cache, null, 2)); + return new Response(pngBuffer, { headers: { "Content-Type": "image/png", -- cgit v1.3.1