import { mkdir, readFile, writeFile } from "node:fs/promises"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { createContentLoader } from "vitepress"; import type { ContentData, SiteConfig } from "vitepress"; import { type SatoriOptions, satoriVue } from "x-satori/vue"; import { renderAsync } from "@resvg/resvg-js"; const __dirname = dirname(fileURLToPath(import.meta.url)); const __fonts = resolve(__dirname, "../fonts"); export async function generateImages(config: SiteConfig) { const pages = await createContentLoader("**/*.md", { excerpt: true }).load(); const template = await readFile(resolve(__dirname, "./Template.vue"), "utf-8"); const fonts: SatoriOptions["fonts"] = [ { name: "Inter", data: await readFile(resolve(__fonts, "Inter-Regular.otf")), weight: 400, style: "normal", }, { name: "Inter", data: await readFile(resolve(__fonts, "Inter-Medium.otf")), weight: 500, style: "normal", }, { name: "Inter", data: await readFile(resolve(__fonts, "Inter-SemiBold.otf")), weight: 600, style: "normal", }, { name: "Inter", data: await readFile(resolve(__fonts, "Inter-Bold.otf")), weight: 700, style: "normal", }, ]; for (const page of pages) { await generateImage({ page, template, outDir: config.outDir, fonts, }); } } interface GenerateImagesOptions { page: ContentData; template: string; outDir: string; fonts: SatoriOptions["fonts"]; } async function generateImage({ page, template, outDir, fonts }: GenerateImagesOptions) { const { frontmatter, url } = page; const options: SatoriOptions = { width: 1200, height: 628, fonts, props: { title: frontmatter.layout === "home" ? frontmatter.hero.name ?? frontmatter.title : frontmatter.title, description: frontmatter.layout === "home" ? frontmatter.hero.tagline ?? frontmatter.description : frontmatter.description, }, }; const svg = await satoriVue(options, template); const render = await renderAsync(svg); const outputFolder = resolve(outDir, url.slice(1), "__og_image__"); const outputFile = resolve(outputFolder, "og.png"); await mkdir(outputFolder, { recursive: true }); return await writeFile(outputFile, render.asPng()); }