9. 성능 최적화

유시온·2024년 8월 18일
18

항해 플러스

목록 보기
9/10
post-thumbnail

항해 플러스 프론트엔드 코스란?

1~4년 차 주니어 프론트엔드 개발자들이 모여 매주 토요일마다 오프라인 모임, 코드 리뷰를 진행하고
평일에 한 번씩 멘토링을 진행하면서 주니어 개발자들이 성장할 수 있는 환경을 제공해 주는 코스입니다.

이번 항해 플러스 프론트엔드 코스 9주 차에선 성능 최적화에 대해서 배웠습니다.
성능 최적화 방법에 대해서 처음 배워보고, 적용해 보아서 새롭게 배운 내용이 많은 주차였습니다.

어떤 내용들을 배웠고, 성급한 최적화는 왜 좋지 않은지 정리해 보겠습니다.

과제 정리

이번 9주 차 과제로는 성능이 안 좋은 프로젝트를 Lighthouse로 측정하며 성능을 개선하는 것이었습니다.

심화 과제로는 직접 개선 사후 보고서를 작성하는 것이었는데요, 제가 직접 제출한 보고서를 첨부하여 어떤 것을 배웠는지 다루어보겠습니다!

성능 측정 개선 사후 보고서

AS-IS TO-BE
First Contentful Paint(FCP): 1.9초 0.8초
Largest Contentful Paint(LCP): 1.9초 0.8초
Total Blocking Time(TBT): 910밀리초 0초
Cumulative Layout Shift(CLS): 0.516 0
Speed Index: 2.7초 2.0초

성능

1. 차세대 형식 이미지 지원 및 이미지 압축

기존 서비스의 문제점은 이미지 로드 시간이 오래 걸려 FCP, LCP 수치가 좋지 않았습니다.

WebP 및 AVIF와 같은 이미지 형식은 PNG나 JPEG보다 압축률이 높기 때문에 다운로드가 빠르고 데이터 소비량도 적습니다.

개선 방식:

  • jpg 형식의 이미지를 차세대 형식인 webp 형식으로 변경하였습니다.
  • 이미지 파일 압축 및 viewport만큼 이미지 크기 조정하였습니다.
AS-IS TO-BE
LCP: 16.4초 8.3초
TBT: 910 밀리초 600 밀리초
이미지 리소스 1,400KiB 140 KiB

주의할 점으로는 webp나 avif는 IE나 오래된 버전의 브라우저는 지원이 안 될 수 있습니다.

브라우저마다 지원되는지 확인할 때 주로 Can I Use 사이트를 이용할 수 있습니다!

2. 오프스크린 이미지 지연 로드

기존 코드의 문제점은 Desktop, Tablet, Mobile 사이즈에 맞는 배너 이미지가 각각 있었는데, Desktop 해상도에도 Tablet, Mobile 이미지를 로드하고 있었습니다.

중요한 리소스의 로드가 모두 완료된 후에는 오프스크린 및 숨겨진 이미지를 지연 로드함으로써 상호작용 시작 시간을 줄이는 것이 좋습니다.

개선 방식: source 태그의 media 속성을 선언하여 특정 화면에 맞는 이미지만 불러오도록 변경하였습니다.

<picture>
  <source
    width="576"
    height="576"
    media="(max-width: 575px)"
    srcset="images/Hero_Mobile.webp"
  />
  <source
    width="960"
    height="770"
    media="(min-width: 576px) and (max-width: 960px)"
    srcset="images/Hero_Tablet.webp"
  />
  <img width="1920px" height="893px" src="images/Hero_Desktop.webp" />
</picture>
AS-IS TO-BE
LCP: 8.1초 3.5초
불필요하게 로드되었언 이미지 리소스 크기: 2,270KiB 0 KiB

3. 렌더링 차단 리소스 제거

기존 코드는 head에 있는 script 태그가 html 렌더링을 지연시키고 있었습니다.

리소스가 페이지의 첫 페인트를 차단하고 있습니다. 중요한 JS/CSS를 인라인으로 전달하고 중요하지 않은 모든 JS/Style을 지연하는 것이 좋습니다.

개선 방식:

  • script 선언 위치를 body 하단으로 옮겼습니다.
  • GTM, cookie consent script defer 속성 지정하였습니다.

async와 defer 속성은 스크립트는 다운로드 시 페이지 렌더링을 막지 않는다는 공통점이 있습니다.
HTML 콘텐츠에 영향을 주지 않는 script라면 상황에 따라 적절히 async, defer를 지정하여 렌더링이 차단되는 점을 개선할 수 있습니다. (참고자료)

  • async: async는 스크립트를 비동기적으로 다운로드하고 즉시 실행
  • defer: defer는 스크립트를 비동기적으로 다운로드하지만 HTML 파싱이 완료된 후에 실행
AS-IS TO-BE
LCP: 8.1초 3.5초
불필요하게 로드되었언 이미지 리소스 크기: 2,270KiB 0 KiB

4. 레이지 로딩 적용

기존 코드의 문제점은 뷰포트에 상품 목록 화면이 보이지 않아도 API 요청과 이미지 로드를 하고 있었습니다.
사용자 입장에서 상품 목록을 요청하지 않아도 페이지에 접속하면 해당 리소스 만큼 로딩을 기다려야 하는 비효율이 발생합니다.

개선 방식: 특정 요소가 뷰포트 내에 노출된다면 그때 무거운 연산을 수행하도록 Intersection Observer를 사용하였습니다.
추가로 이미지가 로드될 때 레이아웃 시프팅 현상이 발생하지 않도록 스켈레톤 UI를 적용하였습니다.

AS-IS TO-BE
TBT: 1,670 밀리초 0 밀리초
자바스크립트 기본 스레드 작업: 2.4초 0.3초

주의해야할 점으로는 화면에서 바로 노출되어야 하는 이미지는 Lazy 로딩을 적용하면 안됩니다.

성능 최적화 과제에 대한 더 자세한 내용은 해당 깃허브 레포지토리에서 확인 가능합니다!

성급한 최적화가 좋지 않은 이유

저는 이번에 새로운 최적화 기법을 배우면서 성급한 최적화가 좋지 않다는 것도 알게 되었습니다.

Lazy Loading 기법을 모든 이미지에 무작정 적용했을 때 첫 화면에 노출되는 배너 이미지의 로딩 속도가 오히려 느려지는 현상을 경험했습니다. 이로 인해 최적화가 항상 긍정적인 결과를 보장하지 않음을 깨닫게 되었습니다!

최적화 보다 더 중요한 것은 최적화가 필요한 부분을 신중하게 식별하고 그에 맞는 적절한 기법을 선택하는 것입니다.

성급한 최적화는 모든 죄악의 근원이다.

마무리

이렇게 9주차에 배운 내용을 다루어 보았습니다!
다양한 성능 최적화 기법들을 배워 어떻게 적용할지 부터 급급하게 생각했는데, "성급한 최적화는 좋지 않다."라는 코치님의 조언이 가장 인상깊었습니다.

각 최적화 기법은 사용하는 상황이 있고, 무분별하게 사용하면 오히려 좋지 않기 때문에 이러한 의미에서 성능 최적화 경험이 많으면 좋을 것 같다고 뼈저리게 느꼈습니다. ㅠㅁㅠ

9주차 후기

실습 기반의 발제 내용과 알찬 과제 구성으로 다양한 개념을 많이 배운 9주차 였습니다.

앞만 보고 달리니 벌써 마지막인 10주차가 다가오네요.
다음 주에는 전체적인 항해 플러스 프론트엔드 코스를 회고하며 마지막 후기 글로 찾아오겠습니다!

긴 글 읽어주셔서 감사합니다 :)

⭐️ 항해 플러스 프론트엔드 코스 3기 모집

제가 현재 참여하고 있는 항해 플러스 프론트엔드 코스가 3기를 모집하고 있다고 하여 공유드립니다!
8월 22일까지 신청하시면 얼리버드 혜택으로 약 40% 할인을 받으실 수 있습니다.

또한 추천인 제도로 [추천인] 코드에 “HHPGS0894”를 입력하시면 20만 원 추가 할인 혜택이 있으니
관심 있으신 분들은 항해 플러스 공식 홈페이지에서 신청하시면 됩니다 :)

저의 1주 차부터 9주 차까지 후기 글을 보시고 항해 플러스 프론트엔드 코스 관련해서 궁금한 사항이 있으시다면 링크드인 메시지 또는 이메일 yoosioff@gmail.com으로 편하게 연락주세요.

profile
프론트엔드를 좋아하는 평범한 주니어 개발자입니다!

2개의 댓글

comment-user-thumbnail
2024년 8월 19일

글 잘 읽었습니다 👍
그런데 첨부해주신 깃허브 레포 링크가 잘 못 연결된 것 같아요!

1개의 답글