fix(ai): sharp via dynamic import, nicht top-level
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 2m28s

Der vorige Versuch mit ssr.external in vite.config.ts war ein No-op:
adapter-node macht einen eigenen Rollup-Bundle-Schritt nach Vite und
ignoriert ssr.external komplett. Ergebnis: sharp's dynamic-require
fuer die native .node-Binary landet kaputt im Server-Bundle (332KB
Bundle-Chunk, 297 sharp-Referenzen).

Dynamic import mit /* @vite-ignore */ verhindert, dass Rollup sharp
aufloest — die Require geht stattdessen zur Laufzeit regulaer an
Node und findet @img/sharp-linuxmusl-arm64 in node_modules.

Ergebnis lokal: Server-Chunk von 332KB auf 14KB geschrumpft, nur noch
2 Referenzen auf den Paketnamen (der Import-String selbst).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-21 12:33:59 +02:00
parent fd7884e1b2
commit 39de08abf9

View File

@@ -1,4 +1,4 @@
import sharp from 'sharp';
import type SharpType from 'sharp';
const MAX_EDGE = 1600;
const JPEG_QUALITY = 85;
@@ -8,10 +8,20 @@ export type PreprocessedImage = {
mimeType: 'image/jpeg';
};
// Dynamic import: adapter-node bundelt server-code via Rollup/@rollup/plugin-commonjs,
// und das packt sharp's dynamic-require fuer die native Plattform-.node-Binary
// kaputt ins Bundle. Mit import() via Vite's Hint-Kommentar kann Rollup sharp
// nicht auflösen und laesst es zur Laufzeit regulaer aus node_modules laden.
async function loadSharp(): Promise<typeof SharpType> {
const mod = await import(/* @vite-ignore */ 'sharp');
return (mod as unknown as { default: typeof SharpType }).default ?? (mod as unknown as typeof SharpType);
}
// Resize auf max 1600px lange Kante, JPEG re-encode, Metadata strippen.
// sharp liest HEIC/HEIF transparent, wenn libheif im libvips-Build enthalten ist
// (in Alpine's vips-dev + in den offiziellen sharp-Prebuilds).
export async function preprocessImage(input: Buffer): Promise<PreprocessedImage> {
const sharp = await loadSharp();
const pipeline = sharp(input, { failOn: 'error' }).rotate(); // respect EXIF orientation
const meta = await pipeline.metadata();
if (!meta.width || !meta.height) {