From 4e7294e4c72394a39e62f451cff13eb19bfafe75 Mon Sep 17 00:00:00 2001 From: Bradley Shellnut Date: Mon, 23 Dec 2024 11:04:14 -0800 Subject: [PATCH] Fixing Svelte OG and Satori implementation. --- package.json | 6 ++-- pnpm-lock.yaml | 47 +++++++++------------------- src/lib/renderImage.ts | 63 +++++++++++++++++++------------------- src/routes/+page.server.ts | 3 +- src/routes/og/+server.ts | 2 +- svelte.config.js | 1 + 6 files changed, 52 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index 1e0a8b2..9f0c43c 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "@biomejs/biome": "^1.9.4", "@playwright/test": "^1.49.1", "@sveltejs/enhanced-img": "^0.4.4", - "@sveltejs/kit": "^2.13.0", + "@sveltejs/kit": "^2.15.0", "@sveltejs/vite-plugin-svelte": "^5.0.3", "@types/nprogress": "^0.2.3", "@unpic/svelte": "^0.0.57", @@ -32,7 +32,7 @@ "postcss-import": "^16.1.0", "postcss-load-config": "^5.1.0", "postcss-preset-env": "^9.6.0", - "satori": "^0.10.14", + "satori": "^0.12.0", "satori-html": "^0.3.2", "svelte": "^5.15.0", "svelte-check": "^4.1.0", @@ -53,7 +53,7 @@ "bits-ui": "1.0.0-next.66", "flexsearch": "^0.7.43", "ioredis": "^5.4.2", - "lucide-svelte": "^0.468.0", + "lucide-svelte": "^0.469.0", "nprogress": "^0.2.0", "scrape-it": "^6.1.3", "sharp": "^0.33.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 70d60d0..a19efb9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 2.6.2 '@sveltejs/adapter-node': 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': specifier: ^0.6.4 version: 0.6.4 @@ -27,8 +27,8 @@ importers: specifier: ^5.4.2 version: 5.4.2 lucide-svelte: - specifier: ^0.468.0 - version: 0.468.0(svelte@5.15.0) + specifier: ^0.469.0 + version: 0.469.0(svelte@5.15.0) nprogress: specifier: ^0.2.0 version: 0.2.0 @@ -52,8 +52,8 @@ importers: specifier: ^0.4.4 version: 0.4.4(rollup@4.28.1)(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) '@sveltejs/kit': - specifier: ^2.13.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)) + specifier: ^2.15.0 + 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': specifier: ^5.0.3 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 version: 9.6.0(postcss@8.4.49) satori: - specifier: ^0.10.14 - version: 0.10.14 + specifier: ^0.12.0 + version: 0.12.0 satori-html: specifier: ^0.3.2 version: 0.3.2 @@ -1176,8 +1176,8 @@ packages: svelte: ^5.0.0 vite: '>= 5.0.0' - '@sveltejs/kit@2.13.0': - resolution: {integrity: sha512-6t6ne00vZx/TjD6s0Jvwt8wRLKBwbSAN1nhlOzcLUSTYX1hTp4eCBaTPB5Yz/lu+tYcvz4YPEEuPv3yfsNp2gw==} + '@sveltejs/kit@2.15.0': + resolution: {integrity: sha512-FI1bhfhFNGI2sKg+BhiRyM4eaOvX+KZqRYSQqL5PK3ZZREX2xufZ6MzZAw79N846OnIxYNqcz/3VOUq+FPDd3w==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -1675,8 +1675,8 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} - lucide-svelte@0.468.0: - resolution: {integrity: sha512-n0ecAFtCY5LEeL+PJ1Xj4n3c2gzj8tMpak0KMGnvoSJEjCsCnRB0mekBtJZAo7beyynW9Qj5Um1KfMBAeTNplw==} + lucide-svelte@0.469.0: + resolution: {integrity: sha512-PMIJ8jrFqVUsXJz4d1yfAQplaGhNOahwwkzbunha8DhpiD73xqX24n8dE1dPpUk3vcrdWVsHc1y/liHHotOnGQ==} peerDependencies: svelte: ^3 || ^4 || ^5.0.0-next.42 @@ -2014,10 +2014,6 @@ packages: satori-html@0.3.2: resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==} - satori@0.10.14: - resolution: {integrity: sha512-abovcqmwl97WKioxpkfuMeZmndB1TuDFY/R+FymrZyiGP+pMYomvgSzVPnbNMWHHESOPosVHGL352oFbdAnJcA==} - engines: {node: '>=16'} - satori@0.12.0: resolution: {integrity: sha512-e0e+qQyeFwEszujN7SpWpRtZgww7Nh8lSO3bUn2spHZ5JpqEl3zJ3P14/JlWruxEwdgREs35ZnavrPrWaRVFDg==} engines: {node: '>=16'} @@ -3120,12 +3116,12 @@ snapshots: fflate: 0.7.4 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: '@rollup/plugin-commonjs': 28.0.2(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) - '@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 '@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: - 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: '@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.15.0)(vite@6.0.5(yaml@2.6.1)) '@types/cookie': 0.6.0 @@ -3697,7 +3693,7 @@ snapshots: loupe@3.1.2: {} - lucide-svelte@0.468.0(svelte@5.15.0): + lucide-svelte@0.469.0(svelte@5.15.0): dependencies: svelte: 5.15.0 @@ -4107,19 +4103,6 @@ snapshots: dependencies: 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: dependencies: '@shuding/opentype.js': 1.4.0-beta.0 diff --git a/src/lib/renderImage.ts b/src/lib/renderImage.ts index 633fe25..bf4f407 100644 --- a/src/lib/renderImage.ts +++ b/src/lib/renderImage.ts @@ -1,4 +1,6 @@ import satori from 'satori'; +import type { Component } from 'svelte'; +import { render } from 'svelte/server'; import { Resvg } from '@resvg/resvg-js'; import { html as toReactNode } from 'satori-html'; 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 import firaSansSemiBold from '$lib/fonts/FiraSans-SemiBold.ttf'; -import type { SvelteComponent } from 'svelte'; const fontData = read(firaSansSemiBold).arrayBuffer(); +export async function componentToPng(component: Component, props: Record, 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, - props: Record, - height: number, width: number) { - const result = component.render(props); - const markup = toReactNode(`${result.html}`); + const svg = await satori(markup, { + fonts: [ + { + name: 'Fira Sans', + data: await fontData, + style: 'normal', + }, + ], + height: +height, + width: +width, + }); - const svg = await satori(markup, { - fonts: [ - { - name: 'Fira Sans', - data: await fontData, - style: 'normal' - } - ], - height: +height, - width: +width - }); + const resvg = new Resvg(svg, { + fitTo: { + mode: 'width', + value: +width, + }, + }); - const resvg = new Resvg(svg, { - fitTo: { - mode: 'width', - value: +width - } - }); + const image = resvg.render(); - const image = resvg.render(); - - return new Response(image.asPng(), { - headers: { - 'content-type': 'image/png', - 'cache-control': dev ? 'no-cache, no-store' : 'public, immutable, no-transform, max-age=86400' - } - }); -} \ No newline at end of file + return new Response(image.asPng(), { + headers: { + 'content-type': 'image/png', + 'cache-control': dev ? 'no-cache, no-store' : 'public, immutable, no-transform, max-age=86400', + }, + }); +} diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index de6d6d5..a3c074a 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1,12 +1,11 @@ import { PUBLIC_SITE_URL } from '$env/static/public'; import type { Album } from '$lib/types/album'; import type { ArticlePageLoad } from '$lib/types/article'; -import { fetchBandcampAlbums } from '$lib/util/fetchBandcampAlbums'; import type { MetaTagsProps } from 'svelte-meta-tags'; import type { PageServerLoad } from './$types'; export const load: PageServerLoad = async ({ fetch, setHeaders, url }) => { - let baseUrl; + let baseUrl: string; if (url.origin.includes('prerender')) { baseUrl = PUBLIC_SITE_URL || 'https://bradleyshellnut.com'; } else { diff --git a/src/routes/og/+server.ts b/src/routes/og/+server.ts index 302f8d6..e4bcc6d 100644 --- a/src/routes/og/+server.ts +++ b/src/routes/og/+server.ts @@ -1,5 +1,5 @@ import SocialImageCard from "$lib/components/socialImageCard.svelte"; -import { componentToPng } from "$root/lib/renderImage"; +import { componentToPng } from "$lib/renderImage"; const height = 630; const width = 1200; diff --git a/svelte.config.js b/svelte.config.js index ab5c5eb..6a514f8 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -19,6 +19,7 @@ const config = { }, compilerOptions: { enableSourcemap: process.env.NODE_ENV === 'development', + css: 'injected' } };