Sharp를 이용해 이미지 Jpeg to WebP 변환 후 S3에 업로드하기

KUKJIN LEE's profile picture

KUKJIN LEE3주 전 작성

이미지 용량을 줄이면 페이지 로딩 속도가 개선되고, 사용자 경험도 좋아집니다. Sharp 라이브러리를 사용하면 JPEG, PNG 등 다양한 포맷의 이미지를 WebP로 간단하게 변환하고, 변환된 이미지를 AWS S3에 업로드 할 수 있습니다.

 

필요

  1. @aws-sdk/client-s3

    • AWS SDK v3 버전으로, S3Client, PutObjectCommand 등을 사용해 S3에 파일을 업로드합니다.

  2. sharp

    • Node.js에서 인기 있는 이미지 처리 라이브러리로, 다양한 포맷 변환, 리사이징, 압축 등을 손쉽게 지원합니다.

  3. 환경 변수(AWS_REGION, AWS_ACCESS_KEY_ID 등)

    • S3 업로드를 위해 필요한 AWS 인증 정보(Region, Access Key, Secret Key), 그리고 업로드할 버킷 이름을 설정합니다.

 

코드분석

uploadImageToS3라는 함수를 만들어 파일 버퍼(Buffer)와 파일 이름, 콘텐츠 타입을 처리한 후, 업로드 하는 구조입니다.

import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import sharp from 'sharp'

const region = process.env.AWS_REGION
const accessKeyId = process.env.AWS_ACCESS_KEY_ID
const secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY
const bucketName = process.env.S3_BUCKET_NAME

let s3: S3Client | null = null

if (region && accessKeyId && secretAccessKey && bucketName) {
  s3 = new S3Client({
    region,
    credentials: {
      accessKeyId,
      secretAccessKey,
    },
  })
} else {
  console.error('S3 기본 설정에 관한 오류')
}

export async function uploadImageToS3(
  fileBuffer: Buffer,
  fileName: string,
  contentType: string,
): Promise<string> {
  if (!s3 || !bucketName) {
    throw new Error('파일을 업로드 할 수 없습니다.')
  }

  try {
    let optimizedBuffer: Buffer
    if (contentType.startsWith('image/')) {
      optimizedBuffer = await sharp(fileBuffer)
        .resize(1920, 1080, {
          fit: 'inside',
          withoutEnlargement: true
        })
        .webp({ quality: 80 })
        .toBuffer()

      // 업로드될 파일 이름을 .webp로 교체
      fileName = fileName.replace(/\.[^/.]+$/, '.webp')
    } else {
      // 이미지가 아닌 경우 그대로 업로드(이 부분에선 webp 변환 X)
      optimizedBuffer = fileBuffer
    }

    // S3에 업로드
    const command = new PutObjectCommand({
      Bucket: bucketName,
      Key: `test/${fileName}`,
      Body: optimizedBuffer,
      ContentType: 'image/webp', // 변환된 이미지의 타입
    })

    await s3.send(command)

    return `test/${fileName}`
  } catch (error) {
    console.error('에러:', error)
    throw new Error('업로드 실패')
  }
}

이미지 변환(Sharp)

  1. .resize(1920, 1080, { fit: 'inside', withoutEnlargement: true })

    • 이미지가 원본보다 클 경우 최대 1920×1080 범위 안으로만 리사이징

    • 원본이 이미 작다면 확대하지 않음

  2. .webp({ quality: 80 })

    • WebP 포맷으로 변환, 품질(quality)을 80으로 지정 → 원본 대비 용량이 상당히 줄면서도 시각적 품질은 크게 떨어지지 않음

  3. .toBuffer()

    • 최종 변환된 이미지를 버퍼 형태로 반환

 

파일 이름 및 S3 업로드

  • 기존 파일 이름 확장자를 .webp로 교체해 업로드

  • ContentType 역시 "image/webp"로 지정해줌

  • Key: 'test/${fileName}' 경로로 S3에 저장 → test/ 폴더 하위에 웹 이미지가 생성됨

 

  1. 환경 변수 설정

    • AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET_NAME가 제대로 설정되어야 정상 작동

    • 코드 내에서 region && accessKeyId && secretAccessKey && bucketName 체크 후 S3를 초기화하지 못하면 에러 메시지 출력

  2. Sharp 설치 버전 확인

    • Node.js 환경에서 Sharp를 설치할 때, OS 및 Node 버전에 따라 바이너리 문제가 날 수 있음(특히 알파인 리눅스에서).

    • 로컬에서 sharp이 정상적으로 동작하는지 확인 필요

  3. 이미지 MIME 타입 처리

    • contentType.startsWith('image/')로 분기 → 이미지 외에는 변환하지 않고 그대로 업로드

    • 이미지가 아닌데 ContentType이 image/로 넘어올 경우, 의도치 않게 WebP 변환 시도가 일어날 수 있으니 주의

  4. S3 권한(Policy) 확인

    • S3에 PutObject 권한이 있는지, 버킷이 존재하는지 확인

    • 잘못된 IAM Role 또는 권한 정책이면 업로드가 실패할 수 있음

 

전형적인 이미지 최적화 예시로, 웹 서비스에서 이미지 로딩 속도를 높이고, 트래픽 비용을 절감하는 데 도움이 됩니다.

New Tech Posts