Fixing Svelte OG and Satori implementation.

This commit is contained in:
Bradley Shellnut 2024-12-23 11:04:14 -08:00
parent 300e2b5912
commit 4e7294e4c7
6 changed files with 52 additions and 70 deletions

View file

@ -21,7 +21,7 @@
"@biomejs/biome": "^1.9.4", "@biomejs/biome": "^1.9.4",
"@playwright/test": "^1.49.1", "@playwright/test": "^1.49.1",
"@sveltejs/enhanced-img": "^0.4.4", "@sveltejs/enhanced-img": "^0.4.4",
"@sveltejs/kit": "^2.13.0", "@sveltejs/kit": "^2.15.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3", "@sveltejs/vite-plugin-svelte": "^5.0.3",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@unpic/svelte": "^0.0.57", "@unpic/svelte": "^0.0.57",
@ -32,7 +32,7 @@
"postcss-import": "^16.1.0", "postcss-import": "^16.1.0",
"postcss-load-config": "^5.1.0", "postcss-load-config": "^5.1.0",
"postcss-preset-env": "^9.6.0", "postcss-preset-env": "^9.6.0",
"satori": "^0.10.14", "satori": "^0.12.0",
"satori-html": "^0.3.2", "satori-html": "^0.3.2",
"svelte": "^5.15.0", "svelte": "^5.15.0",
"svelte-check": "^4.1.0", "svelte-check": "^4.1.0",
@ -53,7 +53,7 @@
"bits-ui": "1.0.0-next.66", "bits-ui": "1.0.0-next.66",
"flexsearch": "^0.7.43", "flexsearch": "^0.7.43",
"ioredis": "^5.4.2", "ioredis": "^5.4.2",
"lucide-svelte": "^0.468.0", "lucide-svelte": "^0.469.0",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"scrape-it": "^6.1.3", "scrape-it": "^6.1.3",
"sharp": "^0.33.5", "sharp": "^0.33.5",

View file

@ -13,7 +13,7 @@ importers:
version: 2.6.2 version: 2.6.2
'@sveltejs/adapter-node': '@sveltejs/adapter-node':
specifier: ^5.2.11 specifier: ^5.2.11
version: 5.2.11(@sveltejs/kit@2.13.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))) version: 5.2.11(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))
'@vercel/og': '@vercel/og':
specifier: ^0.6.4 specifier: ^0.6.4
version: 0.6.4 version: 0.6.4
@ -27,8 +27,8 @@ importers:
specifier: ^5.4.2 specifier: ^5.4.2
version: 5.4.2 version: 5.4.2
lucide-svelte: lucide-svelte:
specifier: ^0.468.0 specifier: ^0.469.0
version: 0.468.0(svelte@5.15.0) version: 0.469.0(svelte@5.15.0)
nprogress: nprogress:
specifier: ^0.2.0 specifier: ^0.2.0
version: 0.2.0 version: 0.2.0
@ -52,8 +52,8 @@ importers:
specifier: ^0.4.4 specifier: ^0.4.4
version: 0.4.4(rollup@4.28.1)(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) version: 0.4.4(rollup@4.28.1)(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))
'@sveltejs/kit': '@sveltejs/kit':
specifier: ^2.13.0 specifier: ^2.15.0
version: 2.13.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) version: 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))
'@sveltejs/vite-plugin-svelte': '@sveltejs/vite-plugin-svelte':
specifier: ^5.0.3 specifier: ^5.0.3
version: 5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) version: 5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))
@ -85,8 +85,8 @@ importers:
specifier: ^9.6.0 specifier: ^9.6.0
version: 9.6.0(postcss@8.4.49) version: 9.6.0(postcss@8.4.49)
satori: satori:
specifier: ^0.10.14 specifier: ^0.12.0
version: 0.10.14 version: 0.12.0
satori-html: satori-html:
specifier: ^0.3.2 specifier: ^0.3.2
version: 0.3.2 version: 0.3.2
@ -1176,8 +1176,8 @@ packages:
svelte: ^5.0.0 svelte: ^5.0.0
vite: '>= 5.0.0' vite: '>= 5.0.0'
'@sveltejs/kit@2.13.0': '@sveltejs/kit@2.15.0':
resolution: {integrity: sha512-6t6ne00vZx/TjD6s0Jvwt8wRLKBwbSAN1nhlOzcLUSTYX1hTp4eCBaTPB5Yz/lu+tYcvz4YPEEuPv3yfsNp2gw==} resolution: {integrity: sha512-FI1bhfhFNGI2sKg+BhiRyM4eaOvX+KZqRYSQqL5PK3ZZREX2xufZ6MzZAw79N846OnIxYNqcz/3VOUq+FPDd3w==}
engines: {node: '>=18.13'} engines: {node: '>=18.13'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -1675,8 +1675,8 @@ packages:
loupe@3.1.2: loupe@3.1.2:
resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==}
lucide-svelte@0.468.0: lucide-svelte@0.469.0:
resolution: {integrity: sha512-n0ecAFtCY5LEeL+PJ1Xj4n3c2gzj8tMpak0KMGnvoSJEjCsCnRB0mekBtJZAo7beyynW9Qj5Um1KfMBAeTNplw==} resolution: {integrity: sha512-PMIJ8jrFqVUsXJz4d1yfAQplaGhNOahwwkzbunha8DhpiD73xqX24n8dE1dPpUk3vcrdWVsHc1y/liHHotOnGQ==}
peerDependencies: peerDependencies:
svelte: ^3 || ^4 || ^5.0.0-next.42 svelte: ^3 || ^4 || ^5.0.0-next.42
@ -2014,10 +2014,6 @@ packages:
satori-html@0.3.2: satori-html@0.3.2:
resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==} resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==}
satori@0.10.14:
resolution: {integrity: sha512-abovcqmwl97WKioxpkfuMeZmndB1TuDFY/R+FymrZyiGP+pMYomvgSzVPnbNMWHHESOPosVHGL352oFbdAnJcA==}
engines: {node: '>=16'}
satori@0.12.0: satori@0.12.0:
resolution: {integrity: sha512-e0e+qQyeFwEszujN7SpWpRtZgww7Nh8lSO3bUn2spHZ5JpqEl3zJ3P14/JlWruxEwdgREs35ZnavrPrWaRVFDg==} resolution: {integrity: sha512-e0e+qQyeFwEszujN7SpWpRtZgww7Nh8lSO3bUn2spHZ5JpqEl3zJ3P14/JlWruxEwdgREs35ZnavrPrWaRVFDg==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -3120,12 +3116,12 @@ snapshots:
fflate: 0.7.4 fflate: 0.7.4
string.prototype.codepointat: 0.2.1 string.prototype.codepointat: 0.2.1
'@sveltejs/adapter-node@5.2.11(@sveltejs/kit@2.13.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))': '@sveltejs/adapter-node@5.2.11(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))':
dependencies: dependencies:
'@rollup/plugin-commonjs': 28.0.2(rollup@4.28.1) '@rollup/plugin-commonjs': 28.0.2(rollup@4.28.1)
'@rollup/plugin-json': 6.1.0(rollup@4.28.1) '@rollup/plugin-json': 6.1.0(rollup@4.28.1)
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.28.1) '@rollup/plugin-node-resolve': 16.0.0(rollup@4.28.1)
'@sveltejs/kit': 2.13.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) '@sveltejs/kit': 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))
rollup: 4.28.1 rollup: 4.28.1
'@sveltejs/enhanced-img@0.4.4(rollup@4.28.1)(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))': '@sveltejs/enhanced-img@0.4.4(rollup@4.28.1)(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))':
@ -3140,7 +3136,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- rollup - rollup
'@sveltejs/kit@2.13.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))': '@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)))(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))':
dependencies: dependencies:
'@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1))
'@types/cookie': 0.6.0 '@types/cookie': 0.6.0
@ -3697,7 +3693,7 @@ snapshots:
loupe@3.1.2: {} loupe@3.1.2: {}
lucide-svelte@0.468.0(svelte@5.15.0): lucide-svelte@0.469.0(svelte@5.15.0):
dependencies: dependencies:
svelte: 5.15.0 svelte: 5.15.0
@ -4107,19 +4103,6 @@ snapshots:
dependencies: dependencies:
ultrahtml: 1.5.3 ultrahtml: 1.5.3
satori@0.10.14:
dependencies:
'@shuding/opentype.js': 1.4.0-beta.0
css-background-parser: 0.1.0
css-box-shadow: 1.0.0-3
css-to-react-native: 3.2.0
emoji-regex: 10.4.0
escape-html: 1.0.3
linebreak: 1.1.0
parse-css-color: 0.2.1
postcss-value-parser: 4.2.0
yoga-wasm-web: 0.3.3
satori@0.12.0: satori@0.12.0:
dependencies: dependencies:
'@shuding/opentype.js': 1.4.0-beta.0 '@shuding/opentype.js': 1.4.0-beta.0

View file

@ -1,4 +1,6 @@
import satori from 'satori'; import satori from 'satori';
import type { Component } from 'svelte';
import { render } from 'svelte/server';
import { Resvg } from '@resvg/resvg-js'; import { Resvg } from '@resvg/resvg-js';
import { html as toReactNode } from 'satori-html'; import { html as toReactNode } from 'satori-html';
import { dev } from '$app/environment'; import { dev } from '$app/environment';
@ -6,42 +8,39 @@ import { read } from '$app/server';
// we use a Vite plugin to turn this import into the result of fs.readFileSync during build // we use a Vite plugin to turn this import into the result of fs.readFileSync during build
import firaSansSemiBold from '$lib/fonts/FiraSans-SemiBold.ttf'; import firaSansSemiBold from '$lib/fonts/FiraSans-SemiBold.ttf';
import type { SvelteComponent } from 'svelte';
const fontData = read(firaSansSemiBold).arrayBuffer(); const fontData = read(firaSansSemiBold).arrayBuffer();
export async function componentToPng(component: Component, props: Record<string, string | undefined>, height: number, width: number) {
const result = render(component, { props });
console.log('result', result);
const markup = toReactNode(`${result.body}${result.head}`);
export async function componentToPng(component: SvelteComponent, const svg = await satori(markup, {
props: Record<string, string | undefined>, fonts: [
height: number, width: number) { {
const result = component.render(props); name: 'Fira Sans',
const markup = toReactNode(`${result.html}<style lang="css">${result.css.code}</style>`); data: await fontData,
style: 'normal',
},
],
height: +height,
width: +width,
});
const svg = await satori(markup, { const resvg = new Resvg(svg, {
fonts: [ fitTo: {
{ mode: 'width',
name: 'Fira Sans', value: +width,
data: await fontData, },
style: 'normal' });
}
],
height: +height,
width: +width
});
const resvg = new Resvg(svg, { const image = resvg.render();
fitTo: {
mode: 'width',
value: +width
}
});
const image = resvg.render(); return new Response(image.asPng(), {
headers: {
return new Response(image.asPng(), { 'content-type': 'image/png',
headers: { 'cache-control': dev ? 'no-cache, no-store' : 'public, immutable, no-transform, max-age=86400',
'content-type': 'image/png', },
'cache-control': dev ? 'no-cache, no-store' : 'public, immutable, no-transform, max-age=86400' });
} }
});
}

View file

@ -1,12 +1,11 @@
import { PUBLIC_SITE_URL } from '$env/static/public'; import { PUBLIC_SITE_URL } from '$env/static/public';
import type { Album } from '$lib/types/album'; import type { Album } from '$lib/types/album';
import type { ArticlePageLoad } from '$lib/types/article'; import type { ArticlePageLoad } from '$lib/types/article';
import { fetchBandcampAlbums } from '$lib/util/fetchBandcampAlbums';
import type { MetaTagsProps } from 'svelte-meta-tags'; import type { MetaTagsProps } from 'svelte-meta-tags';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => { export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => {
let baseUrl; let baseUrl: string;
if (url.origin.includes('prerender')) { if (url.origin.includes('prerender')) {
baseUrl = PUBLIC_SITE_URL || 'https://bradleyshellnut.com'; baseUrl = PUBLIC_SITE_URL || 'https://bradleyshellnut.com';
} else { } else {

View file

@ -1,5 +1,5 @@
import SocialImageCard from "$lib/components/socialImageCard.svelte"; import SocialImageCard from "$lib/components/socialImageCard.svelte";
import { componentToPng } from "$root/lib/renderImage"; import { componentToPng } from "$lib/renderImage";
const height = 630; const height = 630;
const width = 1200; const width = 1200;

View file

@ -19,6 +19,7 @@ const config = {
}, },
compilerOptions: { compilerOptions: {
enableSourcemap: process.env.NODE_ENV === 'development', enableSourcemap: process.env.NODE_ENV === 'development',
css: 'injected'
} }
}; };