본문 바로가기
기타

웹 페이지 최적화하기 - 2

by 유세지 2022. 9. 7.

이전 글에서 이어집니다.

 

지난 포스트에서는 최적화를 왜 해야하는지 알아보고, 자바스크립트 파일의 최적화를 진행하였습니다. 크게 아래의 세 가지 방법을 적용하였습니다.

 

자바스크립트 파일 크기 줄이기

  • 코드 사이의 공백 지우기, 변수 이름 줄이기 (난독화)
  • 사용하지 않는 모듈 빼기 (트리 셰이킹)
  • CSS 파일을 분리하여 최적화하기

 

우리는 자바스크립트 파일의 크기를 줄임으로서 페이지와 처음으로 상호작용 할 수 있는 속도를 앞당겼습니다. 훌륭한 일을 해냈지만, 웹 페이지의 로딩 속도는 여전히 느릴 가능성이 큽니다. 아직 큰 산이 남아있기 때문입니다.

 

 

이미지 최적화 하기

웹 사이트에서 이미지는 뗄래야 뗄 수 없는 요소입니다. 전 세계 어느 사이트를 가더라도 이미지가 포함되지 않은 사이트를 찾기는 어렵습니다. 이미지는 사이트를 다채롭게 만들어주는 중요한 요소지만, 무시할 수 없는 단점이 있습니다. 바로 용량입니다.

 

 

다른 파일들에 비해 압도적인 차이입니다.

 

위 그림은 이번에 성능 개선을 진행하던 프로젝트를 기준으로, 네트워크에 요청한 각 파일들이 가진 크기를 형식별로 나누어 그래프로 나타낸 그림입니다. 확실한 비교를 위해 이전 글에서 진행한 자바스크립트 최적화를 적용하지 않은 상태로 비교하였습니다.

 

이처럼 이미지들은 별다른 처리를 해주지 않을 경우 다른 파일들에 비해 유독 큰 용량을 갖게 됩니다. 우리가 아무리 자바스크립트 최적화를 진행해주더라도, 이 이미지들을 어떻게든 해주지 않으면 최적화를 완료했다고 할 수 없습니다. 지금부터 어떻게 이 무지막지한 용량을 줄여줄 수 있을지 함께 생각해봅시다.

 

 

사진 파일 최적화 하기

우리가 흔히 사용하는 이미지 파일의 형식으로는 무엇이 있을까요? 정말 다양한 형식이 존재하지만, 대표적으로 아래의 두 가지를 꼽을 수 있을 것 같습니다.

 

JPG

JPG는 1992년 JPEG(Joint Photographic Experts Group) 이라는 단체에서 개발한 이미지 포맷입니다. 이미지를 보다 쉽게 공유할 수 있도록 손실 압축 기법을 통해 파일의 크기를 줄인 것이 특징입니다. 손실 압축 기법이다보니 원본보다 화질이 떨어진다는 단점이 있지만, 대신 이미지의 용량이 크게 줄어들어 빠른 전달이 가능해졌습니다.

 

 

PNG

PNG는 Portable Network Graphics의 약자로,  GIF 형식을 대체하기 위해  1996년 PNG Development Group에서 개발되었습니다. 당시 GIF 형식에 사용되는 LZW 데이터 압축 알고리즘의 소유권을 갖고 있던 유니시스가 소프트웨어 특허를 적용할 것이라고 공표하면서, 이에 대한 대안으로 빠르게 개발되었고 기술에 대한 소유권은 웹 표준을 개발하던 W3C에 기부되었습니다.

 

PNG 형식의 특징으로는 무손실 압축과 함께 투명도를 지원한다는 점입니다. 투명도를 지원하지 않는 JPG와 달리, 프로세싱 과정에서 파일에 포함된 데이터를 그대로 갖고 있기 때문에 상대적으로 상당히 큰 용량을 가지고 있습니다.

 

 

JPG는 적은 용량 덕분에 빠르게 불러올 수 있지만 화질이 낮고, PNG는 많은 데이터를 갖고있기 때문에 높은 화질을 갖고 있지만 용량이 큽니다. 각자 장단점이 있는 형식이다 보니 어느 한 쪽을 선뜻 선택하기가 쉽지 않습니다. 적은 용량과 높은 화질을 함께 가질 수는 없을까요?

 

 

WEBP로 변환하기

방법은 있습니다. 바로 Webp 형식을 이용하는겁니다.

Webp는 웹 페이지에서 빠르게 이미지를 표시하기 위해 2010년 구글에서 발표한 이미지 포맷입니다. 기존의 png, jpg 파일을 webp 형식으로 변환할때 손실과 무손실 중 압축 방식을 선택할 수 있으며 무손실의 경우 png 대비 최대 26%의 용량을 줄일 수 있습니다.

 

webp 형식을 사용할 때 한 가지 주의할 점이 있다면 아직 모든 환경에서 완벽히 지원하지는 않는다는 점입니다. 구형 브라우저에서는 이러한 형식이 아예 보이지 않기 때문에 폴백 이미지를 함께 사용해주는 것이 좋습니다. 개발자 도구에 들어가면 webp 형식 지원을 disable하는 버튼도 있으니 궁금하신 분들은 한 번 체크하고 사이트를 이용해보셔도 좋겠네요.

 

2022년 9월 기준으로 webp는 97.17%의 환경에서 지원하고 있습니다.

 

 

최적화 - 이미지 압축

그럼, 본격적으로 이미지의 용량을 낮춰보겠습니다. 위에서 말씀드린 방법들을 적용하는 두 가지 방식이 있는데, 첫 번째는 직접 에셋 파일을 압축하거나 형식을 변경하는 방식입니다. 포토샵 같은 이미지 편집 프로그램을 이용하거나, Squoosh 같은 이미지 편집 사이트들을 이용하셔도 좋습니다.

 

직접 파일을 수정하길 원하지 않는다면 웹팩 플러그인을 통해서도 처리할 수 있습니다. 이미지를 압축시킬 수 있는 몇 가지 플러그인들을 소개해드리겠습니다.

 

 

PNG

우선 플러그인 적용을 위해 ImageMinimizerPlugin을 설치해줍니다.

npm i -D image-minimizer-webpack-plugin
// yarn을 사용한다면,
yarn add -D image-minimizer-webpack-plugin

 

압축을 위해 imagemin을 사용하겠습니다. imagemin에서 지원하는 png 압축 플러그인인 imagemin-optipng도 함께 설치하여 사용해주세요.

npm i -D imagemin imagemin-optipng
// yarn을 사용한다면,
yarn add -D imagemin imagemin-optipng

 

설치가 완료됐다면, webpack.config.js 파일에 적용해줍니다.

const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        type: "asset",
      },
    ],
  },
  optimization: {
    minimize: true,
    minimizer: [
      '...',
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["optipng", { optimizationLevel: 5 }],
            ]
          }
        }
      })
    ]
  }
};

imagemin-optipng의 경우, optimizationLevel을 0~7까지로 설정할 수 있습니다. 압축률에 가장 큰 영향을 미치는 속성이고, 다른 옵션으로는 bitDepthReduction, colorTypeReduction, paletteReduction 등을 boolean 속성으로 제공합니다.

 

압축 전 후 비교 (hero.png)

압축을 진행해주니 용량이 10.7mb에서 7.5mb로 줄어들었고, 로딩 시간도 311밀리초에서 229밀리초로 감소하였습니다.

 

 

WEBP

만약 기존의 png 파일을 webp 파일로 변환하여 이용하고 싶다면 먼저 rules의 generator를 통해 이미지 파일을 변환해주어야 합니다.

 

module: {
  rules: [
    {
      test: /\.png/,
      type: 'asset/rewource',
      generator: {
        filename: 'static/[hash].webp[query]'
      }
    },
  ]
}

 

webp 파일을 생성하는 rule을 생성해주었다면, 이제 webp 파일도 압축해보겠습니다. 아래 명령어를 통해 imagemin-webp 플러그인을 설치해주겠습니다.

 

npm i -D imagemin-webp
// yarn을 사용한다면,
yarn add -D imagemin-webp

 

 

minimizer의 plugins에 방금 설치한 imagemin-webp를 적용해줍니다.

 

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      '...',
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ['imagemin-webp', { quality: 50, resize: { width: 1280, height: 0 } }],
            ]
          }
        }
      })
    ]
  }
};

 

imagemin-optipng와 마찬가지로 최적화 속성이 있습니다. 기본적인 이미지의 화질을 결정하는 quality 속성을 0에서 100사이의 값으로 줄 수 있고, 미지정시 기본값은 75로 설정됩니다. 이 외에도 투명도 퀄리티를 조정하는 alphaQuality, 압축 속도와 품질을 결정하는 method, 이미지의 사이즈를 설정하는 resize 등 다양한 옵션이 존재합니다.

 

직접 수치들을 조절해가며 원하는 최적화 옵션을 찾는게 가장 좋겠지만, 일일히 설정해주기 귀찮거나 잘 모르는 사람들을 위한 preset 옵션도 있습니다.

 

압축 전 후 비교 (95e51a7d7...webp > 0065957...webp)

그냥 webp 파일로 변경했을때엔 용량 494kb에 로딩 시간 16밀리초가 된 반면, 압축 퀄리티 지정과 리사이징을 적용해주니 용량 78.8kb에 로딩 시간 10밀리초가 되었습니다. 원본 png 파일이 10mb가 넘어가던걸 생각하면, 극적인 변화가 아닐 수 없습니다. 지난 시간의 js 최적화와는 비교도 되지 않을 정도로 사이트 로딩 속도가 빨라진게 체감이 되었습니다.

 

Fallback Image

성능은 개선되었지만, 위에서 언급했듯 모든 브라우저 환경이 webp를 지원하지는 않습니다. 이럴때 유용한 것이 바로 Fallback Image, 실패시 다른 이미지를 보여주는 기법입니다.

 

<picture>
    <source srcset="hero.webp" type="image/webp">
    <img src="hero.png">
</picture>

 

기존의 이미지 태그 부분을 picture 태그와 source 태그를 이용해 감싸주고, 마지막에 img 태그를 추가하게 되면, webp를 지원하는 브라우저에선 source 태그의 webp 이미지가, 지원하지 않는 브라우저에서는 img 태그의 png 이미지가 등장하게 됩니다.

 

 

마무리

오늘은 이미지 최적화 과정을 알아보고, 프로젝트에 적용해보았습니다. 사이트 용량의 대부분을 차지하는 컨텐츠기 때문에, 유저의 사용성을 위해 그냥 넘어갈 수 없는 중요한 작업입니다.

 

이번에 사용한 imagemin은 더 이상 maintaining 되지 않는 라이브러리입니다. 따라서 최신 버전의 웹팩과 충돌을 일으키거나 문제가 일어날 가능성이 있지만, 웹팩 공식 문서에 다른 대안으로 소개된 squoosh 등과 비교해서 압축률이나 이미지의 퀄리티가 뛰어나다고 느끼게 되어 사용하게 되었습니다.

 

이후에 심각한 충돌 문제가 생기게 된다면, 다른 플러그인을 사용하는 대안을 고려해보아야 할 것 같습니다. 

읽어주셔서 감사합니다.

 

참고 문서

JPG vs. PNG: Which Should I Use?

PNG - Wikipedia

WebP 파일 - Adobe

ImageMinimizerWebpackPlugin - Webpack

 

반응형

댓글