refactor(backend): 18단계 이미지 처리 최적화 - 메타데이터 중복 조회 제거

- processImage: includeMetadata 옵션 추가
- processImage: sharp 인스턴스 재사용 (clone() 사용)
- uploadAlbumPhoto: 중복 sharp(originalBuffer).metadata() 제거

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-01-21 15:59:14 +09:00
parent b0ac0e51e4
commit fec2a4455c
2 changed files with 25 additions and 13 deletions

View file

@ -24,21 +24,33 @@ const { medium, thumb } = config.image;
/**
* 이미지를 3가지 해상도로 변환
* @param {Buffer} buffer - 원본 이미지 버퍼
* @param {boolean} includeMetadata - 메타데이터 포함 여부
* @returns {Promise<{originalBuffer, mediumBuffer, thumbBuffer, metadata?}>}
*/
async function processImage(buffer) {
async function processImage(buffer, includeMetadata = false) {
const image = sharp(buffer);
// 메타데이터가 필요한 경우 먼저 조회 (중복 sharp 인스턴스 생성 방지)
const metadata = includeMetadata ? await image.metadata() : null;
const [originalBuffer, mediumBuffer, thumbBuffer] = await Promise.all([
sharp(buffer).webp({ lossless: true }).toBuffer(),
sharp(buffer)
image.clone().webp({ lossless: true }).toBuffer(),
image.clone()
.resize(medium.width, null, { withoutEnlargement: true })
.webp({ quality: medium.quality })
.toBuffer(),
sharp(buffer)
image.clone()
.resize(thumb.width, null, { withoutEnlargement: true })
.webp({ quality: thumb.quality })
.toBuffer(),
]);
return { originalBuffer, mediumBuffer, thumbBuffer };
const result = { originalBuffer, mediumBuffer, thumbBuffer };
if (metadata) {
result.metadata = metadata;
}
return result;
}
/**
@ -146,8 +158,7 @@ export async function deleteAlbumCover(folderName) {
* @returns {Promise<{originalUrl: string, mediumUrl: string, thumbUrl: string, metadata: object}>}
*/
export async function uploadAlbumPhoto(folderName, subFolder, filename, buffer) {
const { originalBuffer, mediumBuffer, thumbBuffer } = await processImage(buffer);
const metadata = await sharp(originalBuffer).metadata();
const { originalBuffer, mediumBuffer, thumbBuffer, metadata } = await processImage(buffer, true);
const basePath = `album/${folderName}/${subFolder}`;

View file

@ -186,12 +186,13 @@
---
### 18단계: 이미지 처리 최적화 🔄 진행 예정
- [ ] 이미지 메타데이터 중복 처리 제거
- [ ] processImage에서 메타데이터 함께 반환
### 18단계: 이미지 처리 최적화 ✅ 완료
- [x] 이미지 메타데이터 중복 처리 제거
- [x] processImage에서 메타데이터 함께 반환
- [x] sharp 인스턴스 재사용 (clone() 사용)
**대상 파일:**
- `src/services/image.js` - processImage 함수 개선
**수정된 파일:**
- `src/services/image.js` - processImage 함수 개선, uploadAlbumPhoto 중복 조회 제거
---
@ -245,7 +246,7 @@
| 15단계 | 스키마 파일 분리 | ✅ 완료 |
| 16단계 | 에러 처리 일관성 | ✅ 완료 |
| 17단계 | 중복 코드 제거 (멤버 조회) | ✅ 완료 |
| 18단계 | 이미지 처리 최적화 | 🔄 진행 예정 |
| 18단계 | 이미지 처리 최적화 | ✅ 완료 |
| 19단계 | Redis 캐시 확대 | 🔄 진행 예정 |
| 20단계 | 서비스 레이어 확대 | 🔄 진행 예정 |
| 21단계 | 검색 페이징 최적화 | 🔄 진행 예정 |