From 27507d1d78531901c20a17d9ce72728c6cbb521e Mon Sep 17 00:00:00 2001 From: Sat Naing Date: Wed, 1 Mar 2023 18:46:42 +0630 Subject: [PATCH] feat: generate og images in png format (#43) * feat: generate og images in png format In production mode, generate og images from svg to png format. fix #40 * refactor: update og image format from svg to png Update OG image format in post detail to png. Update twitter og images to auto-generated dynamic og images. --- astro.config.mjs | 5 + package-lock.json | 294 ++++++++++++++++++++++++++++++++++ package.json | 1 + src/layouts/Layout.astro | 9 +- src/layouts/PostDetails.astro | 2 +- src/utils/generateOgImage.tsx | 20 ++- 6 files changed, 320 insertions(+), 11 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index a07746e..717491c 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -33,4 +33,9 @@ export default defineConfig({ }, extendDefaultPlugins: true, }, + vite: { + optimizeDeps: { + exclude: ["@resvg/resvg-js"], + }, + }, }); diff --git a/package-lock.json b/package-lock.json index fbb5488..38badef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "2.1.0", "dependencies": { "@astrojs/rss": "^2.1.0", + "@resvg/resvg-js": "^2.4.1", "astro": "^2.0.8", "fuse.js": "^6.6.2", "github-slugger": "^2.0.0", @@ -1390,6 +1391,208 @@ "escalade": "^3.1.1" } }, + "node_modules/@resvg/resvg-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.4.1.tgz", + "integrity": "sha512-wTOf1zerZX8qYcMmLZw3czR4paI4hXqPjShNwJRh5DeHxvgffUS5KM7XwxtbIheUW6LVYT5fhT2AJiP6mU7U4A==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@resvg/resvg-js-android-arm-eabi": "2.4.1", + "@resvg/resvg-js-android-arm64": "2.4.1", + "@resvg/resvg-js-darwin-arm64": "2.4.1", + "@resvg/resvg-js-darwin-x64": "2.4.1", + "@resvg/resvg-js-linux-arm-gnueabihf": "2.4.1", + "@resvg/resvg-js-linux-arm64-gnu": "2.4.1", + "@resvg/resvg-js-linux-arm64-musl": "2.4.1", + "@resvg/resvg-js-linux-x64-gnu": "2.4.1", + "@resvg/resvg-js-linux-x64-musl": "2.4.1", + "@resvg/resvg-js-win32-arm64-msvc": "2.4.1", + "@resvg/resvg-js-win32-ia32-msvc": "2.4.1", + "@resvg/resvg-js-win32-x64-msvc": "2.4.1" + } + }, + "node_modules/@resvg/resvg-js-android-arm-eabi": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.4.1.tgz", + "integrity": "sha512-AA6f7hS0FAPpvQMhBCf6f1oD1LdlqNXKCxAAPpKh6tR11kqV0YIB9zOlIYgITM14mq2YooLFl6XIbbvmY+jwUw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-android-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.4.1.tgz", + "integrity": "sha512-/QleoRdPfsEuH9jUjilYcDtKK/BkmWcK+1LXM8L2nsnf/CI8EnFyv7ZzCj4xAIvZGAy9dTYr/5NZBcTwxG2HQg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-darwin-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-U1oMNhea+kAXgiEXgzo7EbFGCD1Edq5aSlQoe6LMly6UjHzgx2W3N5kEXCwU/CgN5FiQhZr7PlSJSlcr7mdhfg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-darwin-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.4.1.tgz", + "integrity": "sha512-avyVh6DpebBfHHtTQTZYSr6NG1Ur6TEilk1+H0n7V+g4F7x7WPOo8zL00ZhQCeRQ5H4f8WXNWIEKL8fwqcOkYw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.4.1.tgz", + "integrity": "sha512-isY/mdKoBWH4VB5v621co+8l101jxxYjuTkwOLsbW+5RK9EbLciPlCB02M99ThAHzI2MYxIUjXNmNgOW8btXvw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm64-gnu": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.4.1.tgz", + "integrity": "sha512-uY5voSCrFI8TH95vIYBm5blpkOtltLxLRODyhKJhGfskOI7XkRw5/t1u0sWAGYD8rRSNX+CA+np86otKjubrNg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-arm64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-6mT0+JBCsermKMdi/O2mMk3m7SqOjwi9TKAwSngRZ/nQoL3Z0Z5zV+572ztgbWr0GODB422uD8e9R9zzz38dRQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-x64-gnu": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.4.1.tgz", + "integrity": "sha512-60KnrscLj6VGhkYOJEmmzPlqqfcw1keDh6U+vMcNDjPhV3B5vRSkpP/D/a8sfokyeh4VEacPSYkWGezvzS2/mg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-linux-x64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-0AMyZSICC1D7ge115cOZQW8Pcad6PjWuZkBFF3FJuSxC6Dgok0MQnLTs2MfMdKBlAcwO9dXsf3bv9tJZj8pATA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-arm64-msvc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.4.1.tgz", + "integrity": "sha512-76XDFOFSa3d0QotmcNyChh2xHwk+JTFiEQBVxMlHpHMeq7hNrQJ1IpE1zcHSQvrckvkdfLboKRrlGB86B10Qjw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-ia32-msvc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.4.1.tgz", + "integrity": "sha512-odyVFGrEWZIzzJ89KdaFtiYWaIJh9hJRW/frcEcG3agJ464VXkN/2oEVF5ulD+5mpGlug9qJg7htzHcKxDN8sg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@resvg/resvg-js-win32-x64-msvc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.4.1.tgz", + "integrity": "sha512-vY4kTLH2S3bP+puU5x7hlAxHv+ulFgcK6Zn3efKSr0M0KnZ9A3qeAjZteIpkowEFfUeMPNg2dvvoFRJA9zqxSw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@shuding/opentype.js": { "version": "1.4.0-beta.0", "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", @@ -9734,6 +9937,97 @@ "escalade": "^3.1.1" } }, + "@resvg/resvg-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.4.1.tgz", + "integrity": "sha512-wTOf1zerZX8qYcMmLZw3czR4paI4hXqPjShNwJRh5DeHxvgffUS5KM7XwxtbIheUW6LVYT5fhT2AJiP6mU7U4A==", + "requires": { + "@resvg/resvg-js-android-arm-eabi": "2.4.1", + "@resvg/resvg-js-android-arm64": "2.4.1", + "@resvg/resvg-js-darwin-arm64": "2.4.1", + "@resvg/resvg-js-darwin-x64": "2.4.1", + "@resvg/resvg-js-linux-arm-gnueabihf": "2.4.1", + "@resvg/resvg-js-linux-arm64-gnu": "2.4.1", + "@resvg/resvg-js-linux-arm64-musl": "2.4.1", + "@resvg/resvg-js-linux-x64-gnu": "2.4.1", + "@resvg/resvg-js-linux-x64-musl": "2.4.1", + "@resvg/resvg-js-win32-arm64-msvc": "2.4.1", + "@resvg/resvg-js-win32-ia32-msvc": "2.4.1", + "@resvg/resvg-js-win32-x64-msvc": "2.4.1" + } + }, + "@resvg/resvg-js-android-arm-eabi": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.4.1.tgz", + "integrity": "sha512-AA6f7hS0FAPpvQMhBCf6f1oD1LdlqNXKCxAAPpKh6tR11kqV0YIB9zOlIYgITM14mq2YooLFl6XIbbvmY+jwUw==", + "optional": true + }, + "@resvg/resvg-js-android-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.4.1.tgz", + "integrity": "sha512-/QleoRdPfsEuH9jUjilYcDtKK/BkmWcK+1LXM8L2nsnf/CI8EnFyv7ZzCj4xAIvZGAy9dTYr/5NZBcTwxG2HQg==", + "optional": true + }, + "@resvg/resvg-js-darwin-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-U1oMNhea+kAXgiEXgzo7EbFGCD1Edq5aSlQoe6LMly6UjHzgx2W3N5kEXCwU/CgN5FiQhZr7PlSJSlcr7mdhfg==", + "optional": true + }, + "@resvg/resvg-js-darwin-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.4.1.tgz", + "integrity": "sha512-avyVh6DpebBfHHtTQTZYSr6NG1Ur6TEilk1+H0n7V+g4F7x7WPOo8zL00ZhQCeRQ5H4f8WXNWIEKL8fwqcOkYw==", + "optional": true + }, + "@resvg/resvg-js-linux-arm-gnueabihf": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.4.1.tgz", + "integrity": "sha512-isY/mdKoBWH4VB5v621co+8l101jxxYjuTkwOLsbW+5RK9EbLciPlCB02M99ThAHzI2MYxIUjXNmNgOW8btXvw==", + "optional": true + }, + "@resvg/resvg-js-linux-arm64-gnu": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.4.1.tgz", + "integrity": "sha512-uY5voSCrFI8TH95vIYBm5blpkOtltLxLRODyhKJhGfskOI7XkRw5/t1u0sWAGYD8rRSNX+CA+np86otKjubrNg==", + "optional": true + }, + "@resvg/resvg-js-linux-arm64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-6mT0+JBCsermKMdi/O2mMk3m7SqOjwi9TKAwSngRZ/nQoL3Z0Z5zV+572ztgbWr0GODB422uD8e9R9zzz38dRQ==", + "optional": true + }, + "@resvg/resvg-js-linux-x64-gnu": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.4.1.tgz", + "integrity": "sha512-60KnrscLj6VGhkYOJEmmzPlqqfcw1keDh6U+vMcNDjPhV3B5vRSkpP/D/a8sfokyeh4VEacPSYkWGezvzS2/mg==", + "optional": true + }, + "@resvg/resvg-js-linux-x64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-0AMyZSICC1D7ge115cOZQW8Pcad6PjWuZkBFF3FJuSxC6Dgok0MQnLTs2MfMdKBlAcwO9dXsf3bv9tJZj8pATA==", + "optional": true + }, + "@resvg/resvg-js-win32-arm64-msvc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.4.1.tgz", + "integrity": "sha512-76XDFOFSa3d0QotmcNyChh2xHwk+JTFiEQBVxMlHpHMeq7hNrQJ1IpE1zcHSQvrckvkdfLboKRrlGB86B10Qjw==", + "optional": true + }, + "@resvg/resvg-js-win32-ia32-msvc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.4.1.tgz", + "integrity": "sha512-odyVFGrEWZIzzJ89KdaFtiYWaIJh9hJRW/frcEcG3agJ464VXkN/2oEVF5ulD+5mpGlug9qJg7htzHcKxDN8sg==", + "optional": true + }, + "@resvg/resvg-js-win32-x64-msvc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.4.1.tgz", + "integrity": "sha512-vY4kTLH2S3bP+puU5x7hlAxHv+ulFgcK6Zn3efKSr0M0KnZ9A3qeAjZteIpkowEFfUeMPNg2dvvoFRJA9zqxSw==", + "optional": true + }, "@shuding/opentype.js": { "version": "1.4.0-beta.0", "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", diff --git a/package.json b/package.json index 1f6d9ef..a83f614 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@astrojs/rss": "^2.1.0", + "@resvg/resvg-js": "^2.4.1", "astro": "^2.0.8", "fuse.js": "^6.6.2", "github-slugger": "^2.0.0", diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index b69af82..6f8d9f6 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -24,8 +24,6 @@ const socialImageURL = new URL( ogImage ? ogImage : SITE.ogImage, Astro.url.origin ).href; - -const fallbackImageURL = new URL(SITE.ogImage, Astro.url.origin).href; --- @@ -54,12 +52,7 @@ const fallbackImageURL = new URL(SITE.ogImage, Astro.url.origin).href; - + diff --git a/src/layouts/PostDetails.astro b/src/layouts/PostDetails.astro index ae052da..745f486 100644 --- a/src/layouts/PostDetails.astro +++ b/src/layouts/PostDetails.astro @@ -16,7 +16,7 @@ const { title, author, description, ogImage, pubDatetime, tags } = post.data; const { Content } = await post.render(); -const ogUrl = new URL(ogImage ? ogImage : `${title}.svg`, Astro.url.origin) +const ogUrl = new URL(ogImage ? ogImage : `${title}.png`, Astro.url.origin) .href; --- diff --git a/src/utils/generateOgImage.tsx b/src/utils/generateOgImage.tsx index 0b04b9a..321145e 100644 --- a/src/utils/generateOgImage.tsx +++ b/src/utils/generateOgImage.tsx @@ -1,5 +1,7 @@ import satori, { SatoriOptions } from "satori"; import { SITE } from "@config"; +import { writeFile } from "node:fs/promises"; +import { Resvg } from "@resvg/resvg-js"; const fetchFonts = async () => { // Regular Font @@ -133,7 +135,21 @@ const options: SatoriOptions = { ], }; -const generateOgImage = async (mytext = SITE.title) => - await satori(ogImage(mytext), options); +const generateOgImage = async (mytext = SITE.title) => { + const svg = await satori(ogImage(mytext), options); + + // render png in production mode + if (import.meta.env.MODE === "production") { + const resvg = new Resvg(svg); + const pngData = resvg.render(); + const pngBuffer = pngData.asPng(); + + console.info("Output PNG Image :", `${mytext}.png`); + + await writeFile(`./dist/${mytext}.png`, pngBuffer); + } + + return svg; +}; export default generateOgImage;