feat(seo): site meta composable + Open Graph image generation
Adds `useSiteMeta()` composable that wraps useSeoMeta with site defaults (title template, canonical URL, og/twitter image, og:site_name) and absolute-URL handling via runtimeConfig.public.appUrl. Adds /og/events/[slug].png route that renders per-event OG images via satori + @resvg/resvg-js, cached on disk by slug + updatedAt. Bundles Brygada 1918 + Commit Mono fonts as server assets, ships a fallback default.png, and patches @shuding/opentype.js via patch-package. Converts ~25 pages from useHead to useSiteMeta and adds noindex on private/auth/admin pages.
This commit is contained in:
parent
877ef1a220
commit
31144617d7
36 changed files with 1182 additions and 53 deletions
37
server/utils/og-cache.js
Normal file
37
server/utils/og-cache.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const CACHE_DIR = resolve(__dirname, '../../.cache/og')
|
||||
|
||||
let ensured = false
|
||||
|
||||
async function ensureCacheDir() {
|
||||
if (ensured) return
|
||||
await mkdir(CACHE_DIR, { recursive: true })
|
||||
ensured = true
|
||||
}
|
||||
|
||||
// Returns cached PNG buffer or null. Key must be safe for a filename.
|
||||
export async function getCachedOG(key) {
|
||||
await ensureCacheDir()
|
||||
try {
|
||||
return await readFile(resolve(CACHE_DIR, `${key}.png`))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function setCachedOG(key, buffer) {
|
||||
await ensureCacheDir()
|
||||
await writeFile(resolve(CACHE_DIR, `${key}.png`), buffer)
|
||||
}
|
||||
|
||||
// Build a safe, deterministic cache key from event slug + updatedAt timestamp.
|
||||
// Slug is already URL-safe; updatedAt busts the cache on any edit.
|
||||
export function eventCacheKey(event) {
|
||||
const slug = String(event.slug || event._id).replace(/[^a-zA-Z0-9_-]/g, '_')
|
||||
const stamp = event.updatedAt ? new Date(event.updatedAt).getTime() : 0
|
||||
return `event-${slug}-${stamp}`
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue