[최적화] 포트폴리오 웹페이지 성능 39점 올리기(feat. Lighthouse)

seovee·2024년 1월 20일
0
post-thumbnail

✔ 최적화가 필요한 이유?

비즈니스에 큰 영향을 끼치기 때문이다.

웹사이트의 속도가 느리면 검색 엔진 순위가 떨어지고 전반적인 사이트 이용이 줄어들고 부정적인 사용자 경험이 쌓이다 보면 결국 비즈니스에 영향을 주게 된다. 다양하고 편한 프레임워크가 생겨났지만 전체적으로 웹사이트들이 무거워지면서 자연스럽게 성능 최적화에 관심이 많아지게 된 것이다.

그래서 가장 많이 사용되는 Lighthouse를 이용해서 성능을 측정하고 최적화한 것을 포스팅해보겠다.

✔ First Score

크롬 시크릿 모드 개발 환경에서 Lighthouse를 실행하였다.
왜? 로드 성능에 영향을 미치는 데이터나 확장프로그램이 있을 수 있기 때문이다!

NextJS로 포트폴리오를 만들고 완전 처음으로 Lighthouse를 돌려보았다.
결과는...? 뚜둥

성능(Performance)

웹페이지의 로딩 과정에서 발생하는 성능을 측정, 화면에 콘텐츠 표시되는 시간, 상호작용까지의 시간, 화면에 불안정한 요소가 없는지 등을 확인한다.

접근성(Accessibility)

대체 텍스트가 작성이 되었는지, 배경색과 콘텐츠 색상의 대비가 충분한지, 적절한 WAI-ARIA 속성을 사용했는지 확인한다.

권장사항(Best Practices)

웹 표준 모범사례를 잘 따르고 있는지 확인한다. HTTPS 프로토콜을 사용하는지, 콘솔 창에 오류가 없는 지 등을 확인한다.

검색엔진 최적화(Search Engine Optimization: SEO)

검색 엔진 최적화가 잘 되어 있는지 확인한다. meta 요소는 잘 작성되었는지, 텍스트 크기가 읽기에 무리 없는지 등을 확인한다.

예상대로 첫 포트폴리오라 어떠한 고려도 하지 않은 설계로 성능 점수가 당연히 낮게 나왔다. 다른 부분들은 NextJS의 이점과 기본적인 사항만 지켜줘도 높은 점수를 받을 수 있기 때문에 이번에는 "성능"에 관해서만 포스트해보겠다.

Lighthouse에서는 무엇을 개선해야하는지 포인트를 집어주는 아주 좋은 기능이 있다. 나의 포트폴리오에서 가장 두드러지게 보이는 것은 최대 페인트 요소(LCP)네트워크 페이로드 관련 부분이 문제가 많아보였다.

대부분 힌트를 통해서 개선 방법을 찾을 수 있었는데, 비이상적인 저 수치에 대한 내용은 몇 시간 동안 구글링했지만, /page/index.js의 chunk 파일이 대략 7,000KiB 정도로 잡혀 문제일 뿐 더 이상의 힌트는 없었다. 그냥 가장 처음나오는 페이지가 엄청 크단다. 뭐지??

[용어정리]
* chunk : 하나의 번들 파일을 효과적으로 다루기 위해 여러가지의 파일로 다시 나누는 것

일단 개념정리부터 해보자. 😎


✔ 개념정리

LCP(Largest Contentful Paint)

화면에서 가장 큰 컨텐츠 요소가 화면에 렌더링되는 시간을 측정한 수치이다. 다시말해 사용자에게 보여지는데 걸리는 시간을 측정하는 것을 말한다. 우수한 LCP 점수는 사이트의 최대 콘텐츠 렌더링 시간이 2.5초 이하여야 한다. 가장 기본적으로 큰 사이즈의 <image>, <video>, <svg> 등 용량을 줄이는 것이 대부분의 해결방법이다.

  • 콘텐츠가 포함된 최대 페인트 요소
  • 렌더링 차단 리소스 제거하기
  • 사용하지 않는 자바스크립트 줄이기
  • CSS 축소하기
  • 자바스크립트 줄이기
  • 네트워크 페이로드가 커지지 않도록 관리하기

TBT(Total Blocking Time)

"총 차단 시간"이라하며 사용자 입력으로부터 페이지가 응답하지 못하도록 차단된 총 시간을 측정한 수치이다. 기본 스레드는 기본 스레드에서 50밀리초(ms) 넘게 실행되는 긴 작업이 있을 때마다 진행을 중단할 수 없으므로 기본 스레드가 '차단'되었다고 한다. 따라서 사용자는 긴 작업 도중에 페이지와 상호작용하는 경우에는 50밀리초(ms) 이상의 작업에서 페이지가 느리거나 버벅거린다고 인식할 수 있는 것이다. 우수한 TBT는 평균 모바일 하드웨어에서 테스트할 때 총 차단 시간이 200밀리초(ms) 미만이 되도록 해야한다.

  • 자바스크립트 실행 시간 단축
  • 기본 스레드 작업 최소화하기

최적화 시도한 것들을 아래에 정리해보았다.


✔ 최적화 시도 1 : 이미지 최적화

LCP 성능에 큰 영향을 주고 투자대비 성능 효율이 가장 좋은 최적화 방법이다.

1) <Image>로 webp, avif 적용

NextJS에서는 <img> 말고 자체적으로 제공하는 <Image>를 사용하면 구글이 개발한 이미지 형식인 webp가 기본적으로 적용된다. webp는 PNG, JPEG 등 기존 형식보다 압축률이 좋아 적은 용량을 가지고 있는 포맷이다. 그런데 그것보다 더 압축률이 좋은 avif형식(webp보다 20% 압축률 좋음)을 우선적으로 적용시키면 전체 용량을 절약할 수 있다.

next.config.js에 들어가서 추가해준다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    formats: ["image/avif", "image/webp"],
  },
};
  • webp으로 적용되었을 때는 이정도의 크기이고,
  • avif으로 적용되었을 때는 소폭으로 압축되는 것을 볼 수 있다. 현재는 이미지가 많지 않은 페이지라 이정도지만, 이미지가 많은 웹페이지면 유의미적인 성능을 개선할 수 있는 부분이다.

2) priority, lazy loading 속성 추가

이러한 방법을 사용해도 미미한 수치의 변화뿐이였고 노란불이 아직 꺼지지 않았다. <Image>태그에 대해서 좀 더 깊게 공부를 해서 두번째 최적화때 정리를 해봐야겠다.


✔ 최적화 시도 2 : 폰트 최적화

1) 폰트 선언 중복 정리

2) font-display:swap 추가

두가지 방법을 사용했지만, 변화는 굉장히 미미했다. 약 100KiB정도만 줄은걸로 판단된다. 다음 최적화때는 woff폰트를 직접 로컬에 다운받아서 적용해볼 예정이다.


✔ 하지만 결국 원인은?

이미지, 폰트는 성능 하락폭이 미미했다.
그런데! 구글링하다가 발견한 나도 사용하고 있는 React-icons이 성능저하 원인이며, 그것을 해결한 블로그를 우연히 발견하게 된 것.

React-icons의 Chunk 파일을 크게 만드는 이슈가 원인!

20개 정도 귀여운 아이콘 사용한 React-icons의 chunk 사이즈가 크게 잡혀있는 것이 화근이였다.
react-icon 하나를 사용하려면 js파일에 아이콘 전체를 포함하고 있기 때문에 build시에 chunk 사이즈가 크게 만들어지게 되는 것이었다. 그래서 react-icons에서 @react-icons/all-files 라는 별도의 라이브러리를 제공해 빌드 시 TreeShaking 방식으로 적은 chunk 사이즈를 만들어준다고 한다.

1) 기존 라이브러리 삭제 → 새로운 라이브러리 설치

npm remove react-icons       // 기존 라이브러리
npm i @react-icons/all-files // 새로운 라이브러리

2) Import 주소 변경

새로운 라이브러리에 적용이 안되는 아이콘도 있으므로 일일히 자동완성으로 검색해보고 형식을 맞춰 Import를 하면 된다.

// 기존 코드
import { FaGithub } from "react-icons/fa/FaGitub"
import { MdEmail } from "react-icons/md/MdEmail"

// 개선 코드
import { FaGithub } from "@react-icons/all-files/fa/FaGithub";
import { MdEmail } from "@react-icons/all-files/md/MdEmail";

그럼 기존 그대로 icon을 사용하지만, 다시 chunk을 크기를 확인해보면 대폭 줄은 것을 확인할 수 있을 것이다.


✔ 개선 후

첫번째 최적화에서는 3가지 문제점을 개선하였다.

  1. React-icons를 최적화 → 약 7,000KiB 이상 감소
  2. document.js속 필요없는 프리텐다드 폰트 <link>정리 → 약 90KiB 감소
  3. 불필요한 import, 코드 정리 → 미미

성능 점수는 무려 44점 → 83점 39점이나 상승하였고,
LCP는 11.6초 → 2.8초, TBT는 1,230ms → 120ms로 줄어들었다.

최대 페인트 요소 11,620ms → 2,720ms약 9초 감소,
페이로드 관리도 12,566KiB → 3,766KiB8,800KiB 개선된 수치를 보였다.

첫번째 최적화를 통해서 프론트엔드의 새로운 희열(?!)을 느낄 수 있었고, 생각보다 높은 점수 향상과 힌트가 많이 줄어 너무 기분이 좋았다. 또한, 확실히 포트폴리오 페이지에 들어갈 때 쾌적해진 느낌도 들었다 🥹
두번째 최적화땐 90점을 목표로 세부적인 개선으로 작성해보겠다. 그럼 끝!


참고

📌 프론트엔드 개발자 버들님 참고 블로그
📌 react-icons 성능개선 부분 참고 블로그
📌 코드 스플리팅, dynamic import 참고 블로그

profile
낭만이 빠지면 섭하지

0개의 댓글