feat: image optimization — client-side resize + server-side thumbnails
Avatars/banners now resize to max 512px/1920px and convert to WebP before upload (zero server cost). Chat image uploads generate an 800px-wide WebP thumbnail via Sharp; the feed shows the thumbnail, click opens the full-res original. Adds lazy loading to avatars. Federation-compatible: remote instances without this feature fall back gracefully.
This commit is contained in:
@@ -83,6 +83,7 @@ export function buildDmMessageWithUser(
|
||||
originalName: a.originalName,
|
||||
mimetype: a.mimetype,
|
||||
size: a.size,
|
||||
thumbnailFilename: a.thumbnailFilename ?? null,
|
||||
createdAt: a.createdAt,
|
||||
})),
|
||||
reactions,
|
||||
|
||||
@@ -143,6 +143,7 @@ export function buildMessageWithUser(
|
||||
originalName: a.originalName,
|
||||
mimetype: a.mimetype,
|
||||
size: a.size,
|
||||
thumbnailFilename: a.thumbnailFilename ?? null,
|
||||
createdAt: a.createdAt,
|
||||
})),
|
||||
reactions,
|
||||
|
||||
@@ -8,6 +8,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { pipeline } from 'stream/promises';
|
||||
import type { Attachment } from '@backspace/shared';
|
||||
import { generateThumbnail, isResizableImage } from '../utils/thumbnail.js';
|
||||
|
||||
export async function uploadRoutes(app: FastifyInstance): Promise<void> {
|
||||
// Ensure upload directory exists
|
||||
@@ -57,6 +58,12 @@ export async function uploadRoutes(app: FastifyInstance): Promise<void> {
|
||||
const now = Date.now();
|
||||
const db = getDb();
|
||||
|
||||
// Generate thumbnail for resizable images (non-blocking — upload succeeds regardless)
|
||||
let thumbnailFilename: string | null = null;
|
||||
if (isResizableImage(mimetype)) {
|
||||
thumbnailFilename = await generateThumbnail(filepath, mimetype, config.uploadDir);
|
||||
}
|
||||
|
||||
// Save attachment record
|
||||
db.insert(schema.attachments).values({
|
||||
id,
|
||||
@@ -64,6 +71,7 @@ export async function uploadRoutes(app: FastifyInstance): Promise<void> {
|
||||
originalName,
|
||||
mimetype,
|
||||
size,
|
||||
thumbnailFilename,
|
||||
createdAt: now,
|
||||
}).run();
|
||||
|
||||
@@ -74,6 +82,7 @@ export async function uploadRoutes(app: FastifyInstance): Promise<void> {
|
||||
originalName,
|
||||
mimetype,
|
||||
size,
|
||||
thumbnailFilename: thumbnailFilename ?? undefined,
|
||||
createdAt: now,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user