[우아한테크코스 미션] 성능최적화 1 - 요청 크기 줄이기(소스코드, 이미지 중심)

김예지·2022년 9월 18일
30

우아한테크코스

목록 보기
5/8

우아한테크코스 level4의 첫번째 미션은 웹페이지 성능최적화 였습니다.
성능이 좋지 않은 웹페이지를 최적화하여 성능 점수를 높히는 미션이였어요.
'성능 최적화'는 완전 처음 하는 작업이였기 때문에, 많은 자료를 찾으며 미션을 진행했습니다.
총 4단계에 거쳐 최적화 작업을 진행하였고 결론적으로 lighthouse 측정 기준으로 73점 → 100점으로 개선할 수 있었습니다 🥳
총 4단계에 거쳐서 최적화 작업을 진행했다 라고 했는데, 각각의 단계에서 어떻게 최적화를 했고, 각 단계에서 알게 된 내용들을 정리해보려고 합니다.
4단계는 다음과 같습니다.

  1. 요청 크기 줄이기
  2. 필요한 것만 요청하기
  3. 같은 건 매번 새로 요청하지 않기
  4. 최소한의 변경만 일으키기

오늘은 이 중 첫번째인 1. 요청 크기 줄이기 에 대한 이야기를 해보겠습니다.

요청 크기 줄이기가 뭐야?

Chrome DevTools > Network 메뉴에 들어가면, 웹페이지에 접속했을 때 보내는 요청을 확인할 수 있습니다.
이때, 요청을 보내는 것에 대한 목록과 각각의 요청 크기를 확인해 볼 수 있는데요, 이 요청 크기를 줄이면 성능을 더 개선할 수 있습니다. 아무래도 요청 크기가 크면 다운 받는 시간이 오래 걸리고, 사용자가 콘텐츠를 볼 수 있는데까지의 시간이 오래걸리기 때문이겠죠?
웹페이지에서 요청하는 리소스 타입 중에서도 텍스트인 소스코드(JS, CSS), 이미지가 특히 요청 크기를 많이 잡아먹을 수 있습니다.
그래서 소스코드이미지의 요청 크기를 줄이는 방법을 정리해볼게요. 😄

소스 코드 줄이기

Javascript 소스코드 줄이기

minify & uglify란?

  • minify: 압축하기 (컴퓨터가 코드를 해석하는데 불필요한 부분들을 제거-세미콜론, 공백, 개행 등)
  • uglify: 난독화 (변수명, 함수명을 변경해서 해석을 어렵게합니다. 이를 통해 외부인이 변수 및 함수를 봤을 때 무슨 역할인지 모르도록 할 수 있기 때문에 보안 기능을 가집니다.)

webpack에서 javascript 코드를 minify & uglify 하기
webpack version 4 이상부터는 기본적으로 production 빌드에서 js 코드를 난독화해주고 디버거 구문을 제거합니다.
이때, webpack에서는 terser-webpack-plugin을 사용해서 압축을 해준다고 해요. 따라서, 기본적으로 production모드로 빌드를 해주면 더 용량을 압축할 수 있다는 것이죠.
만약 추가적인 옵션을 추가해주고싶다면 terser-webpack-plugin을 따로 설치해서 옵션을 추가해주어야합니다.
아래에서 dev모드, prod모드로 배포했을 때의 각각의 파일 크기를 확인할 수 있습니다.


dev(위) 모드로 빌드했을 때보다 production(아래) 모드로 빌드했을 때 전체적으로 약 2배정도 크기가 줄었죠?

저는 여기에서 추가적인 옵션 설정이 필요해서, terser-webpack-plugin을 따로 설치해준 후 옵션을 더해주었습니다.
기본적인 minify & uglify 동작에서 추가적인 옵션을 작성해줌으로써 개발자가 원하는 방향대로 압축화 및 난독화할 수 있습니다.

new TerserPlugin({
        terserOptions: {
          format: {
            comments: false // 주석 보존할지의 여부 (일부주석은 보존하도록 설정가능)
          },
          compress: {
            drop_console: true // 콘솔로그를 지우는 것 
          }
        },
        extractComments: false // 주석 파일 추출 여부 
  })

gzip으로 javascript 소스코드 줄이기
여기서 더 줄이려면, gzip을 통해 줄여줄 수도 있습니다.
gzip은 압축 프로그램으로써, 서버에서 소스코드를 압축하는 방식입니다.
저는 위 스텝인 webpack에서 제공해주는 minify & uglify 과정으로도 소스코드가 약 2배 이상 줄었기 때문에 gzip과정은 생략했습니다. 😄

CSS 소스코드 줄이기

CssMinimizerWebpackPlugin
CssMinimizerWebpackPlugin을 통해, css에서 컴퓨터가 해석하는데 불필요한 코드 삭제할 수 있습니다.

MiniCssExtractPlugin
js 파일 하나당 css 파일 하나로, css 파일을 분리할 수 있습니다. 이후 두번째 과정인 2. 필요한 것만 요청하기 를 위해 미리 설정해준 것입니다. 1단계에서는 사실 필요없는 부분이지만, 2단계에서 페이지별로 필요한 css만 가지고 오기 위해 미리 분리해주었어요.

css in js
추가적으로, css in js 코드는 babel transpile 과정에서 minify가 자동으로 된다고 합니다.

이미지 크기 줄이기


이미지 크기 줄이는게 정말 쉽지 않았습니다... 😅 미션 전체 과정에서 가장 오랜 시간을 투자한 부분이였어요. 하지만 그만큼 효과도 확실하게 보장되는 작업이여서 매우 뿌듯했던 기억이 납니다! 평균적으로 웹 페이지 용량에서 이미지가 차지하는 비율이 60% 이상이나 된다고 하니, 이미지 크기만 잘 줄여도 멋진 성능 최적화 효과를 볼 수 있겠죠?
프로젝트 코드에있었던 .gif, .png 이미지의 크기를 줄인 방법을 정리해볼게요.

webpack의 image-minimizer-webpack-plugin

webpack의 image-minimizer-webpack-plugin 을 사용해서, 우리 코드에 있는 .gif, .png의 이미지 크기를 줄여보았습니다.
gif는 imagemin-gifsicle, png는 imagemin-optipng를 적용해주었습니다.
webpack.config.js 내부 코드는 다음과 같이 적용해주었어요.

optimization: {
    minimize: true,
    minimizer: [
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ['gifsicle', { interlaced: true, colors: 60, optimizationLevel: 3 }],
              ['optipng', { optimizationLevel: 4 }] //1~3 level:7.7MB, 4~7 level:7.6MB
            ]
          }
        }
      })
    ]
  }

결과는... 실패입니다 😓
gif, png가 줄어들긴 했지만, 미미한 결과네요. 새로운 방법을 찾아봐야합니다.

webp를 적용해서 png 크기 줄이기

png의 크기를 줄이기 위해서는, png 확장자를 webp로 변경해주면 된다는 것을 알게됩니다.
webp는 구글에서 개발한 이미지 포맷으로, 웹에서 사용되는 gif, png, jpg 이미지 포맷을 대치함으로써 기존 이미지 포맷보다 파일 크기가 약 25~35% 더 작아집니다. 아래의 webp 브라우저 호환성에서 볼 수 있듯, 대부분의 브라우저에서 webp를 제공해주고 있어요. (97% 이상이 사용 가능)

imagemin-webp 를 사용하여 webp로 확장자를 변경해주니, png의 크기가 매우 작아졌습니다. 게다가, 위 스텝에서 적용해주었던 optipng는 webp를 적용하니 필요가 없어졌습니다.

['gifsicle', { interlaced: true, optimizationLevel: 0 }],
['webp', { quality: 50, resize: { width: 1920, height: 0 } }]

이미지 크기를 적절하게 조절하기

현재 desktop 기준(1920 x 1080)으로 이미지를 불러오면 되는데, png 사이즈를 보면 불필요하게 큰 이미지를 불러오고 있습니다. (4100 x 2735)

불필요하게 큰 이미지는 불러오는데 오래 걸리고 용량도 더 크게 잡아먹습니다. 따라서, 이미지 크기를 적절하게 조절하는 작업을 해보겠습니다. desktop 기준으로, 1920만큼의 크기를 불러올 수 있도록 조정해주었습니다.

여기서 잠깐! 👀
만약 레티나 화면을 대응해야한다면, 이미지 크기를 너무 줄여도 안되겠죠?
레티나 화면에서 깨지지 않게 대응하려면, 이미지 크기를 보통 *2 해줍니다.
화면 크기마다 대응하기 위해, 여러 사이즈의 이미지를 준비하는 것도 방법이 될 수 있겠네요.

또한, webp 변환의 옵션인 quality(0~100)는 육안으로 봤을 때 너무 깨져보이지 않도록 50으로 주었습니다. quality에 따라 용량이 엄청 달라졌고, 당연히 quality를 낮게할수록 용량이 작아졌기 때문에 10~40정도로 낮게 하고자 했지만 메인 이미지가 너무 깨져보이는 현상이 생겼습니다.
따라서, 육안으로 봤을 때 적당한 quality 50을 선택했습니다.
(자세한 옵션에 대한 설명은 imagemin-webp의 npm 페이지를 참고해주세요 😊)

여기까지 진행해준 결과는 다음과 같습니다. 용량이 (1.7MB → 137KB) 로 엄청나게 줄었네요!

gif를 mp4로 변환하기

위 작업까지 진행해준 후 lighthouse를 돌려보니, lighthouse 보고서에 다음과 같은 추천 작업이 추가되었습니다.

'애니메이션 콘텐츠에 동영상 형식 사용하기', 이건 어떻게 하는걸까요?
찾아보니 gif는 mp4보다 훨씬 많은 용량을 잡아먹는다고 합니다. 그래서, 만약 웹에 동적인 이미지를 반드시 넣고싶을 때는 mp4로 변환하면 성능상 더 좋다고 해요.
gif를 mp4로 변환하여 대체시켜주고, 적절하게 태그를 바꾸어주었습니다 (img태그 → video 태그).
용량이 얼마나 줄어들었는지 확인해보겠습니다.
결과는 대대대 성공이네요! 용량 줄어든거 보이시죠? 😎

이미지 크기 줄이기 최종 결과

결론적으로, 15.6MB였던 static 폴더를 746KB까지 줄일 수 있었어요.
정리해보자면 gif는 mp4로 변환하면서 사이즈를 크게 줄일 수 있었고, png는 webp를 통해 크게 줄일 수 있었습니다.

정리


1단계, '요청 크기 줄이기' 에 대한 정리를 마쳤습니다.
1단계 최적화까지 마친 페이지는 73점에서 85점이 되었습니다.
4단계까지 최적화하는 과정을 보여드리며, 어떻게 100점을 만들어가는지 정리해볼게요!
2단계 글에서 보아요 👋

profile
내가 짱이다 😎 매일 조금씩 성장하기🌱

0개의 댓글