From 92f80542e6d0e3fec842bee1f04bacb945effff6 Mon Sep 17 00:00:00 2001 From: Froidefond Julien Date: Sun, 22 Mar 2026 06:38:46 +0100 Subject: [PATCH] perf: skip Next.js image re-optimization and stream proxy responses Thumbnails are already optimized (WebP) by the API, so disable Next.js image optimization to avoid redundant CPU work. Switch route handlers from buffering (arrayBuffer) to streaming (response.body) to reduce memory usage and latency. Co-Authored-By: Claude Opus 4.6 --- .../api/books/[bookId]/pages/[pageNum]/route.ts | 15 ++++++--------- .../app/api/books/[bookId]/thumbnail/route.ts | 15 +++++++-------- apps/backoffice/next.config.mjs | 1 + 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/apps/backoffice/app/api/books/[bookId]/pages/[pageNum]/route.ts b/apps/backoffice/app/api/books/[bookId]/pages/[pageNum]/route.ts index 12f17f2..d5c3d06 100644 --- a/apps/backoffice/app/api/books/[bookId]/pages/[pageNum]/route.ts +++ b/apps/backoffice/app/api/books/[bookId]/pages/[pageNum]/route.ts @@ -21,19 +21,16 @@ export async function GET( const response = await fetch(apiUrl.toString(), { headers: { Authorization: `Bearer ${token}` }, }); - + if (!response.ok) { - return new NextResponse(`Failed to fetch image: ${response.status}`, { - status: response.status + return new NextResponse(`Failed to fetch image: ${response.status}`, { + status: response.status }); } - - // Récupérer le content-type et les données + const contentType = response.headers.get("content-type") || "image/webp"; - const imageBuffer = await response.arrayBuffer(); - - // Retourner l'image avec le bon content-type - return new NextResponse(imageBuffer, { + + return new NextResponse(response.body, { headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=300", diff --git a/apps/backoffice/app/api/books/[bookId]/thumbnail/route.ts b/apps/backoffice/app/api/books/[bookId]/thumbnail/route.ts index c412c3e..55e6185 100644 --- a/apps/backoffice/app/api/books/[bookId]/thumbnail/route.ts +++ b/apps/backoffice/app/api/books/[bookId]/thumbnail/route.ts @@ -6,23 +6,22 @@ export async function GET( { params }: { params: Promise<{ bookId: string }> } ) { const { bookId } = await params; - + try { const { baseUrl, token } = config(); const response = await fetch(`${baseUrl}/books/${bookId}/thumbnail`, { headers: { Authorization: `Bearer ${token}` }, }); - + if (!response.ok) { - return new NextResponse(`Failed to fetch thumbnail: ${response.status}`, { - status: response.status + return new NextResponse(`Failed to fetch thumbnail: ${response.status}`, { + status: response.status }); } - + const contentType = response.headers.get("content-type") || "image/webp"; - const imageBuffer = await response.arrayBuffer(); - - return new NextResponse(imageBuffer, { + + return new NextResponse(response.body, { headers: { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable", diff --git a/apps/backoffice/next.config.mjs b/apps/backoffice/next.config.mjs index d366921..54ffc0b 100644 --- a/apps/backoffice/next.config.mjs +++ b/apps/backoffice/next.config.mjs @@ -4,6 +4,7 @@ const nextConfig = { typedRoutes: true, images: { minimumCacheTTL: 86400, + unoptimized: true, }, };